diff --git a/.github/scripts/codeql_buildscript.sh b/.github/scripts/codeql_buildscript.sh index 3e523775f..388f3680d 100755 --- a/.github/scripts/codeql_buildscript.sh +++ b/.github/scripts/codeql_buildscript.sh @@ -126,6 +126,16 @@ if [[ $? != 0 ]]; then exit 1; fi +# build iwasm with multi-memory enabled +cd ${WAMR_DIR}/product-mini/platforms/linux +rm -rf build && mkdir build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_MULTI_MEMORY=1 +make -j +if [[ $? != 0 ]]; then + echo "Failed to build iwasm with multi-memory enabled!" + exit 1; +fi + # build iwasm with hardware boundary check disabled cd ${WAMR_DIR}/product-mini/platforms/linux rm -rf build && mkdir build && cd build @@ -280,3 +290,23 @@ if [[ $? != 0 ]]; then echo "Failed to build iwasm with linux perf support enabled!" exit 1; fi + +# build iwasm with shared heap enabled +cd ${WAMR_DIR}/product-mini/platforms/linux +rm -rf build && mkdir build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_SHARED_HEAP=1 +make -j +if [[ $? != 0 ]]; then + echo "Failed to build iwasm with shared heap enabled!" + exit 1; +fi + +# build iwasm with dynamic aot debug enabled +cd ${WAMR_DIR}/product-mini/platforms/linux +rm -rf build && mkdir build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_DYNAMIC_AOT_DEBUG=1 +make -j +if [[ $? != 0 ]]; then + echo "Failed to build iwasm dynamic aot debug enabled!" + exit 1; +fi diff --git a/.github/workflows/build_docker_images.yml b/.github/workflows/build_docker_images.yml index d5bf682c4..f7643af3f 100644 --- a/.github/workflows/build_docker_images.yml +++ b/.github/workflows/build_docker_images.yml @@ -15,9 +15,14 @@ on: type: string required: true +permissions: + contents: read + jobs: build-and-push-images: runs-on: ubuntu-22.04 + permissions: + contents: write # for uploading release artifacts steps: - name: Checkout repository diff --git a/.github/workflows/build_iwasm_release.yml b/.github/workflows/build_iwasm_release.yml index 887020853..74c2340af 100644 --- a/.github/workflows/build_iwasm_release.yml +++ b/.github/workflows/build_iwasm_release.yml @@ -31,9 +31,78 @@ on: type: string required: false +env: + DEFAULT_BUILD_OPTIONS: + "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 \ + -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \ + -DWAMR_BUILD_DEBUG_INTERP=0 \ + -DWAMR_BUILD_DEBUG_AOT=0 \ + -DWAMR_BUILD_DUMP_CALL_STACK=0 \ + -DWAMR_BUILD_LIBC_UVWASI=0 \ + -DWAMR_BUILD_LIBC_EMCC=0 \ + -DWAMR_BUILD_LIB_RATS=0 \ + -DWAMR_BUILD_LOAD_CUSTOM_SECTION=0 \ + -DWAMR_BUILD_MEMORY_PROFILING=0 \ + -DWAMR_BUILD_MINI_LOADER=0 \ + -DWAMR_BUILD_MULTI_MODULE=0 \ + -DWAMR_BUILD_PERF_PROFILING=0 \ + -DWAMR_BUILD_SPEC_TEST=0 \ + -DWAMR_BUILD_BULK_MEMORY=1 \ + -DWAMR_BUILD_LIB_PTHREAD=1 \ + -DWAMR_BUILD_LIB_PTHREAD_SEMAPHORE=1 \ + -DWAMR_BUILD_LIB_WASI_THREADS=1 \ + -DWAMR_BUILD_LIBC_BUILTIN=1 \ + -DWAMR_BUILD_LIBC_WASI=1 \ + -DWAMR_BUILD_REF_TYPES=1 \ + -DWAMR_BUILD_SIMD=1 \ + -DWAMR_BUILD_SHARED_MEMORY=1 \ + -DWAMR_BUILD_TAIL_CALL=1 \ + -DWAMR_BUILD_THREAD_MGR=1" + GC_EH_BUILD_OPTIONS: + "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=0 \ + -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \ + -DWAMR_BUILD_DEBUG_INTERP=0 \ + -DWAMR_BUILD_DEBUG_AOT=0 \ + -DWAMR_BUILD_DUMP_CALL_STACK=0 \ + -DWAMR_BUILD_LIBC_UVWASI=0 \ + -DWAMR_BUILD_LIBC_EMCC=0 \ + -DWAMR_BUILD_LIB_RATS=0 \ + -DWAMR_BUILD_LOAD_CUSTOM_SECTION=0 \ + -DWAMR_BUILD_MEMORY_PROFILING=0 \ + -DWAMR_BUILD_MINI_LOADER=0 \ + -DWAMR_BUILD_MULTI_MODULE=0 \ + -DWAMR_BUILD_PERF_PROFILING=0 \ + -DWAMR_BUILD_SPEC_TEST=0 \ + -DWAMR_BUILD_BULK_MEMORY=1 \ + -DWAMR_BUILD_LIB_PTHREAD=1 \ + -DWAMR_BUILD_LIB_PTHREAD_SEMAPHORE=1 \ + -DWAMR_BUILD_LIB_WASI_THREADS=1 \ + -DWAMR_BUILD_LIBC_BUILTIN=1 \ + -DWAMR_BUILD_LIBC_WASI=1 \ + -DWAMR_BUILD_REF_TYPES=1 \ + -DWAMR_BUILD_SIMD=1 \ + -DWAMR_BUILD_SHARED_MEMORY=1 \ + -DWAMR_BUILD_TAIL_CALL=1 \ + -DWAMR_BUILD_THREAD_MGR=1 \ + -DWAMR_BUILD_EXCE_HANDLING=1 \ + -DWAMR_BUILD_GC=1" + +permissions: + contents: read + jobs: build: runs-on: ${{ inputs.runner }} + strategy: + matrix: + include: + - build_options: $DEFAULT_BUILD_OPTIONS + suffix: '' + - build_options: $GC_EH_BUILD_OPTIONS + suffix: '-gc-eh' + permissions: + contents: write # for uploading release artifacts + steps: - uses: actions/checkout@v4 @@ -51,40 +120,25 @@ jobs: fail-on-cache-miss: true - name: generate iwasm binary release + shell: bash run: | - cmake -S . -B build \ - -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 \ - -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \ - -DWAMR_BUILD_DEBUG_INTERP=0 \ - -DWAMR_BUILD_DEBUG_AOT=0 \ - -DWAMR_BUILD_DUMP_CALL_STACK=0 \ - -DWAMR_BUILD_LIBC_UVWASI=0 \ - -DWAMR_BUILD_LIBC_EMCC=0 \ - -DWAMR_BUILD_LIB_RATS=0 \ - -DWAMR_BUILD_LOAD_CUSTOM_SECTION=0 \ - -DWAMR_BUILD_MEMORY_PROFILING=0 \ - -DWAMR_BUILD_MINI_LOADER=0 \ - -DWAMR_BUILD_MULTI_MODULE=0 \ - -DWAMR_BUILD_PERF_PROFILING=0 \ - -DWAMR_BUILD_SPEC_TEST=0 \ - -DWAMR_BUILD_BULK_MEMORY=1 \ - -DWAMR_BUILD_LIB_PTHREAD=1 \ - -DWAMR_BUILD_LIB_PTHREAD_SEMAPHORE=1 \ - -DWAMR_BUILD_LIB_WASI_THREADS=1 \ - -DWAMR_BUILD_LIBC_BUILTIN=1 \ - -DWAMR_BUILD_LIBC_WASI=1 \ - -DWAMR_BUILD_REF_TYPES=1 \ - -DWAMR_BUILD_SIMD=1 \ - -DWAMR_BUILD_SHARED_MEMORY=1 \ - -DWAMR_BUILD_TAIL_CALL=1 \ - -DWAMR_BUILD_THREAD_MGR=1 + cmake -S . -B build ${{ matrix.build_options }} cmake --build build --config Release --parallel 4 working-directory: ${{ inputs.cwd }} - - name: compress the binary + - name: Compress the binary on Windows + if: inputs.runner == 'windows-latest' run: | - tar czf iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm - zip iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.zip iwasm + tar -czf iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm.exe + Compress-Archive -Path iwasm.exe -DestinationPath iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.zip + mv iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.* ../ + working-directory: ${{ inputs.cwd }}/build/Release + + - name: compress the binary on non-Windows + if: inputs.runner != 'windows-latest' + run: | + tar czf iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm + zip iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.zip iwasm working-directory: ${{ inputs.cwd }}/build - name: upload release tar.gz @@ -93,8 +147,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ inputs.upload_url }} - asset_path: ${{ inputs.cwd }}/build/iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz - asset_name: iwasm-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.tar.gz + asset_path: ${{ inputs.cwd }}/build/iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz + asset_name: iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.tar.gz asset_content_type: application/x-gzip - name: upload release zip @@ -103,6 +157,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ inputs.upload_url }} - asset_path: ${{ inputs.cwd }}/build/iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.zip - asset_name: iwasm-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.zip + asset_path: ${{ inputs.cwd }}/build/iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.zip + asset_name: iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.zip asset_content_type: application/zip diff --git a/.github/workflows/build_llvm_libraries.yml b/.github/workflows/build_llvm_libraries.yml index 5cde57209..bdfd4fcb2 100644 --- a/.github/workflows/build_llvm_libraries.yml +++ b/.github/workflows/build_llvm_libraries.yml @@ -27,6 +27,9 @@ on: description: "A cached key of LLVM libraries" value: ${{ jobs.build_llvm_libraries.outputs.key}} +permissions: + contents: read + jobs: build_llvm_libraries: runs-on: ${{ inputs.os }} @@ -36,6 +39,9 @@ jobs: image: ${{ inputs.container_image }} outputs: key: ${{ steps.create_lib_cache_key.outputs.key}} + permissions: + contents: read + actions: write # for uploading cached artifact steps: - name: checkout @@ -43,6 +49,7 @@ jobs: - name: install dependencies for non macos-14 if: inputs.os != 'macos-14' + shell: bash run: /usr/bin/env python3 -m pip install -r requirements.txt working-directory: build-scripts @@ -51,10 +58,13 @@ jobs: run: /usr/bin/env python3 -m pip install -r requirements.txt --break-system-packages working-directory: build-scripts - - name: retrieve the last commit ID + - name: Retrieve the last commit ID id: get_last_commit - run: echo "last_commit=$(GH_TOKEN=${{ secrets.GITHUB_TOKEN }} /usr/bin/env python3 ./build_llvm.py ${{ inputs.extra_build_llvm_options }} --llvm-ver)" >> $GITHUB_OUTPUT - working-directory: build-scripts + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + echo "last_commit=$(GH_TOKEN=${{ secrets.GITHUB_TOKEN }} /usr/bin/env python3 ./build_llvm.py ${{ inputs.extra_build_llvm_options }} --llvm-ver)" >> $GITHUB_OUTPUT # Bump the prefix number to evict all previous caches and # enforce a clean build, in the unlikely case that some @@ -62,7 +72,9 @@ jobs: # suspect. - name: form the cache key of libraries id: create_lib_cache_key - run: echo "key=0-llvm-libraries-${{ inputs.os }}-${{ inputs.arch }}-${{ steps.get_last_commit.outputs.last_commit }}${{ inputs.cache_key_suffix }}" >> $GITHUB_OUTPUT + shell: bash + run: | + echo "key=0-llvm-libraries-${{ inputs.os }}-${{ inputs.arch }}-${{ steps.get_last_commit.outputs.last_commit }}${{ inputs.cache_key_suffix }}" >> $GITHUB_OUTPUT - name: Cache LLVM libraries id: retrieve_llvm_libs @@ -107,7 +119,20 @@ jobs: - run: brew install ccache ninja if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'macos') + - uses: actions/cache@v4 + with: + path: ~/.cache/ccache + key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }} + restore-keys: | + 0-ccache-${{ inputs.os }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'windows-latest' + + # Install tools on Windows + - run: choco install -y ccache ninja + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'windows-latest' + - name: Build LLVM libraries if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' + shell: bash run: /usr/bin/env python3 ./build_llvm.py ${{ inputs.extra_build_llvm_options }} --arch ${{ inputs.arch }} working-directory: build-scripts diff --git a/.github/workflows/build_wamr_lldb.yml b/.github/workflows/build_wamr_lldb.yml index 03474c53e..b5cf53a4c 100644 --- a/.github/workflows/build_wamr_lldb.yml +++ b/.github/workflows/build_wamr_lldb.yml @@ -28,8 +28,13 @@ on: required: false default: "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-linux.tar.gz" +permissions: + contents: read + jobs: try_reuse: + permissions: + contents: write # for uploading release artifacts uses: ./.github/workflows/reuse_latest_release_binaries.yml with: binary_name_stem: "wamr-lldb-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}" @@ -46,6 +51,9 @@ jobs: PYTHON_VERSION: '3.10' PYTHON_UBUNTU_STANDALONE_BUILD: https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-unknown-linux-gnu-install_only.tar.gz PYTHON_MACOS_STANDALONE_BUILD: https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-apple-darwin-install_only.tar.gz + permissions: + contents: write # for uploading release artifacts + steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build_wamr_sdk.yml b/.github/workflows/build_wamr_sdk.yml index 519bf9636..266c3a646 100644 --- a/.github/workflows/build_wamr_sdk.yml +++ b/.github/workflows/build_wamr_sdk.yml @@ -35,9 +35,15 @@ on: type: string required: true +permissions: + contents: read + jobs: build: runs-on: ${{ inputs.runner }} + permissions: + contents: write # for uploading release artifacts + steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build_wamr_vscode_ext.yml b/.github/workflows/build_wamr_vscode_ext.yml index 756215e60..d0fa3b18e 100644 --- a/.github/workflows/build_wamr_vscode_ext.yml +++ b/.github/workflows/build_wamr_vscode_ext.yml @@ -14,9 +14,15 @@ on: type: string required: true +permissions: + contents: read + jobs: build: runs-on: ubuntu-22.04 + permissions: + contents: write # for uploading release artifacts + steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build_wamrc.yml b/.github/workflows/build_wamrc.yml index 7c4dab039..6b687c749 100644 --- a/.github/workflows/build_wamrc.yml +++ b/.github/workflows/build_wamrc.yml @@ -31,9 +31,15 @@ on: type: string required: false +permissions: + contents: read + jobs: build: runs-on: ${{ inputs.runner }} + permissions: + contents: write # for uploading release artifacts + steps: - uses: actions/checkout@v4 @@ -56,8 +62,16 @@ jobs: cmake --build build --config Release --parallel 4 working-directory: wamr-compiler - - name: compress the binary - if: inputs.release + - name: Compress the binary on Windows + if: inputs.runner == 'windows-latest' && inputs.release + run: | + tar -czf wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamrc.exe + Compress-Archive -Path wamrc.exe -DestinationPath wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.zip + mv wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.* ../ + working-directory: wamr-compiler/build/Release + + - name: compress the binary on non-Windows + if: inputs.runner != 'windows-latest' && inputs.release run: | tar czf wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamrc zip wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.zip wamrc diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5a9c12d33..b458606c0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -19,6 +19,9 @@ on: # allow to be triggered manually workflow_dispatch: +permissions: + contents: read + jobs: analyze: if: github.repository == 'bytecodealliance/wasm-micro-runtime' @@ -30,10 +33,6 @@ jobs: # Consider using larger runners for possible analysis time improvements. runs-on: ${{ (matrix.language == 'swift' && 'macos-13') || 'ubuntu-22.04' }} timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} - permissions: - actions: read - contents: read - security-events: write strategy: fail-fast: false @@ -41,6 +40,11 @@ jobs: language: [ 'cpp' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ] + permissions: + contents: read + actions: read + security-events: write + steps: - name: Checkout repository uses: actions/checkout@v3 @@ -49,7 +53,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v3.26.13 with: languages: ${{ matrix.language }} @@ -66,7 +70,7 @@ jobs: - run: | ./.github/scripts/codeql_buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v3.26.13 with: category: "/language:${{matrix.language}}" upload: false @@ -95,14 +99,14 @@ jobs: output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif - name: Upload CodeQL results to code scanning - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v3.26.13 with: sarif_file: ${{ steps.step1.outputs.sarif-output }} category: "/language:${{matrix.language}}" - name: Upload CodeQL results as an artifact if: success() || failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v4.4.3 with: name: codeql-results path: ${{ steps.step1.outputs.sarif-output }} diff --git a/.github/workflows/coding_guidelines.yml b/.github/workflows/coding_guidelines.yml index b0aa0a2b8..569237778 100644 --- a/.github/workflows/coding_guidelines.yml +++ b/.github/workflows/coding_guidelines.yml @@ -14,6 +14,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: compliance_job: runs-on: ubuntu-20.04 diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 249a6f276..8ba6e0e80 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -70,8 +70,14 @@ env: MEMORY64_TEST_OPTIONS: "-s spec -W -b -P" MULTI_MEMORY_TEST_OPTIONS: "-s spec -E -b -P" +permissions: + contents: read + jobs: build_llvm_libraries_on_ubuntu_2204: + permissions: + contents: read + actions: write uses: ./.github/workflows/build_llvm_libraries.yml with: os: "ubuntu-22.04" @@ -578,6 +584,15 @@ jobs: ./run.sh test1 ./run.sh test2 + - name: Build Sample [shared-heap] + run: | + cd samples/shared-heap + mkdir build && cd build + cmake .. + cmake --build . --config Debug --parallel 4 + ./shared_heap_test + ./shared_heap_test --aot + test: needs: [ diff --git a/.github/workflows/compilation_on_macos.yml b/.github/workflows/compilation_on_macos.yml index 3b92f4525..66938905c 100644 --- a/.github/workflows/compilation_on_macos.yml +++ b/.github/workflows/compilation_on_macos.yml @@ -52,13 +52,22 @@ env: LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" +permissions: + contents: read + jobs: build_llvm_libraries_on_intel_macos: + permissions: + contents: read + actions: write uses: ./.github/workflows/build_llvm_libraries.yml with: os: "macos-13" arch: "X86" build_llvm_libraries_on_arm_macos: + permissions: + contents: read + actions: write uses: ./.github/workflows/build_llvm_libraries.yml with: os: "macos-14" @@ -386,3 +395,12 @@ jobs: ./build.sh ./run.sh test1 ./run.sh test2 + + - name: Build Sample [shared-heap] + run: | + cd samples/shared-heap + mkdir build && cd build + cmake .. + cmake --build . --config Debug --parallel 4 + ./shared_heap_test + ./shared_heap_test --aot diff --git a/.github/workflows/compilation_on_nuttx.yml b/.github/workflows/compilation_on_nuttx.yml index 2f8014fac..ef0799b42 100644 --- a/.github/workflows/compilation_on_nuttx.yml +++ b/.github/workflows/compilation_on_nuttx.yml @@ -46,6 +46,9 @@ concurrency: env: WASI_SDK_PATH: "/opt/wasi-sdk" +permissions: + contents: read + jobs: build_iwasm_on_nuttx: runs-on: ubuntu-latest @@ -119,11 +122,12 @@ jobs: run: make -j$(nproc) EXTRAFLAGS=-Werror - name: Checkout Bloaty - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: google/bloaty submodules: recursive path: bloaty + ref: 34f4a66559ad4938c1e629e9b5f54630b2b4d7b0 - name: Build Bloaty run: | diff --git a/.github/workflows/compilation_on_sgx.yml b/.github/workflows/compilation_on_sgx.yml index b7bc216eb..70597c366 100644 --- a/.github/workflows/compilation_on_sgx.yml +++ b/.github/workflows/compilation_on_sgx.yml @@ -54,8 +54,14 @@ env: LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" +permissions: + contents: read + jobs: build_llvm_libraries: + permissions: + contents: read + actions: write uses: ./.github/workflows/build_llvm_libraries.yml with: os: "ubuntu-20.04" diff --git a/.github/workflows/compilation_on_windows.yml b/.github/workflows/compilation_on_windows.yml index 8c5db4fdf..369980ba9 100644 --- a/.github/workflows/compilation_on_windows.yml +++ b/.github/workflows/compilation_on_windows.yml @@ -53,6 +53,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: build: runs-on: windows-latest diff --git a/.github/workflows/create_tag.yml b/.github/workflows/create_tag.yml index 5480592a9..7a90ea5f7 100644 --- a/.github/workflows/create_tag.yml +++ b/.github/workflows/create_tag.yml @@ -15,6 +15,9 @@ on: description: "the new tag just created" value: ${{ jobs.create_tag.outputs.new_tag}} +permissions: + contents: read + jobs: create_tag: runs-on: ubuntu-latest @@ -22,6 +25,8 @@ jobs: minor_version: ${{ steps.preparation.outputs.minor_version }} new_ver: ${{ steps.preparation.outputs.new_ver }} new_tag: ${{ steps.preparation.outputs.new_tag }} + permissions: + contents: write # create and push tags steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/hadolint_dockerfiles.yml b/.github/workflows/hadolint_dockerfiles.yml index c540649c8..f9d8c3893 100644 --- a/.github/workflows/hadolint_dockerfiles.yml +++ b/.github/workflows/hadolint_dockerfiles.yml @@ -28,6 +28,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: run-hadolint-on-dockerfiles: runs-on: ubuntu-22.04 diff --git a/.github/workflows/nightly_run.yml b/.github/workflows/nightly_run.yml index f39085d09..5e9b4a4f2 100644 --- a/.github/workflows/nightly_run.yml +++ b/.github/workflows/nightly_run.yml @@ -44,13 +44,22 @@ env: X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P" WASI_TEST_OPTIONS: "-s wasi_certification -w" +permissions: + contents: read + jobs: build_llvm_libraries_on_ubuntu_2004: + permissions: + contents: read + actions: write uses: ./.github/workflows/build_llvm_libraries.yml with: os: "ubuntu-20.04" arch: "X86" build_llvm_libraries_on_ubuntu_2204: + permissions: + contents: read + actions: write uses: ./.github/workflows/build_llvm_libraries.yml with: os: "ubuntu-22.04" @@ -593,6 +602,15 @@ jobs: exit $? working-directory: ./wamr-app-framework/samples/simple + - name: Build Sample [shared-heap] + run: | + cd samples/shared-heap + mkdir build && cd build + cmake .. + cmake --build . --config Debug --parallel 4 + ./shared_heap_test + ./shared_heap_test --aot + test: needs: [ diff --git a/.github/workflows/release_process.yml b/.github/workflows/release_process.yml index 2dce1b55c..031d57884 100644 --- a/.github/workflows/release_process.yml +++ b/.github/workflows/release_process.yml @@ -18,11 +18,18 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: create_tag: + permissions: + contents: write # create and push tags uses: ./.github/workflows/create_tag.yml create_release: + permissions: + contents: write # create release needs: [create_tag] runs-on: ubuntu-latest outputs: @@ -52,6 +59,9 @@ jobs: # # LLVM_LIBRARIES build_llvm_libraries_on_ubuntu_2004: + permissions: + contents: read + actions: write needs: [create_tag, create_release] uses: ./.github/workflows/build_llvm_libraries.yml with: @@ -59,6 +69,9 @@ jobs: arch: "AArch64 ARM Mips RISCV X86" build_llvm_libraries_on_ubuntu_2204: + permissions: + contents: read + actions: write needs: [create_tag, create_release] uses: ./.github/workflows/build_llvm_libraries.yml with: @@ -66,15 +79,30 @@ jobs: arch: "AArch64 ARM Mips RISCV X86" build_llvm_libraries_on_macos: + permissions: + contents: read + actions: write needs: [create_tag, create_release] uses: ./.github/workflows/build_llvm_libraries.yml with: os: "macos-13" arch: "AArch64 ARM Mips RISCV X86" + build_llvm_libraries_on_windows: + permissions: + contents: read + actions: write + needs: [create_tag, create_release] + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "windows-latest" + arch: "AArch64 ARM Mips RISCV X86" + # # WAMRC release_wamrc_on_ubuntu_2004: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2004] uses: ./.github/workflows/build_wamrc.yml with: @@ -85,6 +113,8 @@ jobs: ver_num: ${{ needs.create_tag.outputs.new_ver}} release_wamrc_on_ubuntu_2204: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2204 ] uses: ./.github/workflows/build_wamrc.yml with: @@ -95,6 +125,8 @@ jobs: ver_num: ${{ needs.create_tag.outputs.new_ver }} release_wamrc_on_ubuntu_macos: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release, build_llvm_libraries_on_macos] uses: ./.github/workflows/build_wamrc.yml with: @@ -103,10 +135,24 @@ jobs: runner: macos-13 upload_url: ${{ needs.create_release.outputs.upload_url }} ver_num: ${{ needs.create_tag.outputs.new_ver }} + + release_wamrc_on_windows: + permissions: + contents: write # upload release artifact + needs: [create_tag, create_release, build_llvm_libraries_on_windows] + uses: ./.github/workflows/build_wamrc.yml + with: + llvm_cache_key: ${{ needs.build_llvm_libraries_on_windows.outputs.cache_key }} + release: true + runner: windows-latest + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver }} # # IWASM release_iwasm_on_ubuntu_2004: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2004] uses: ./.github/workflows/build_iwasm_release.yml with: @@ -117,6 +163,8 @@ jobs: ver_num: ${{ needs.create_tag.outputs.new_ver}} release_iwasm_on_ubuntu_2204: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2204] uses: ./.github/workflows/build_iwasm_release.yml with: @@ -127,6 +175,8 @@ jobs: ver_num: ${{ needs.create_tag.outputs.new_ver}} release_iwasm_on_macos: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release, build_llvm_libraries_on_macos] uses: ./.github/workflows/build_iwasm_release.yml with: @@ -136,9 +186,23 @@ jobs: upload_url: ${{ needs.create_release.outputs.upload_url }} ver_num: ${{ needs.create_tag.outputs.new_ver}} + release_iwasm_on_windows: + permissions: + contents: write # upload release artifact + needs: [create_tag, create_release, build_llvm_libraries_on_windows] + uses: ./.github/workflows/build_iwasm_release.yml + with: + cwd: product-mini/platforms/windows + llvm_cache_key: ${{ needs.build_llvm_libraries_on_windows.outputs.cache_key }} + runner: windows-latest + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + # # WAMR_SDK release_wamr_sdk_on_ubuntu_2004: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release] uses: ./.github/workflows/build_wamr_sdk.yml with: @@ -150,6 +214,8 @@ jobs: wamr_app_framework_url: https://github.com/bytecodealliance/wamr-app-framework.git release_wamr_sdk_on_ubuntu_2204: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release] uses: ./.github/workflows/build_wamr_sdk.yml with: @@ -161,6 +227,8 @@ jobs: wamr_app_framework_url: https://github.com/bytecodealliance/wamr-app-framework.git release_wamr_sdk_on_macos: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release] uses: ./.github/workflows/build_wamr_sdk.yml with: @@ -174,6 +242,8 @@ jobs: # # vscode extension cross-platform release_wamr_ide_vscode_ext: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release] uses: ./.github/workflows/build_wamr_vscode_ext.yml secrets: inherit @@ -184,6 +254,8 @@ jobs: # # vscode extension docker images package release_wamr_ide_docker_images_package: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release] uses: ./.github/workflows/build_docker_images.yml with: @@ -193,6 +265,8 @@ jobs: # # WAMR_LLDB release_wamr_lldb_on_ubuntu_2004: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release] uses: ./.github/workflows/build_wamr_lldb.yml with: @@ -201,6 +275,8 @@ jobs: ver_num: ${{ needs.create_tag.outputs.new_ver}} release_wamr_lldb_on_ubuntu_2204: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release] uses: ./.github/workflows/build_wamr_lldb.yml with: @@ -209,6 +285,8 @@ jobs: ver_num: ${{ needs.create_tag.outputs.new_ver}} release_wamr_lldb_on_macos_universal: + permissions: + contents: write # upload release artifact needs: [create_tag, create_release] uses: ./.github/workflows/build_wamr_lldb.yml with: diff --git a/.github/workflows/reuse_latest_release_binaries.yml b/.github/workflows/reuse_latest_release_binaries.yml index c9832cec9..77fe7329f 100644 --- a/.github/workflows/reuse_latest_release_binaries.yml +++ b/.github/workflows/reuse_latest_release_binaries.yml @@ -22,11 +22,17 @@ on: result: value: ${{ jobs.build.outputs.result }} +permissions: + contents: read + jobs: reuse: runs-on: ubuntu-latest outputs: result: ${{ steps.try_reuse.outputs.result }} + permissions: + contents: write # for creating realease and uploading release artifacts + steps: - uses: actions/checkout@v4 # Full git history is needed to get a proper list of commits and tags diff --git a/.github/workflows/spec_test_on_nuttx.yml b/.github/workflows/spec_test_on_nuttx.yml index f2e59ba68..31427d43f 100644 --- a/.github/workflows/spec_test_on_nuttx.yml +++ b/.github/workflows/spec_test_on_nuttx.yml @@ -29,8 +29,14 @@ env: LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" WASI_SDK_PATH: "/opt/wasi-sdk" +permissions: + contents: read + jobs: build_llvm_libraries: + permissions: + contents: read + actions: write uses: ./.github/workflows/build_llvm_libraries.yml with: os: "ubuntu-22.04" @@ -38,6 +44,9 @@ jobs: container_image: ghcr.io/no1wudi/nuttx/apache-nuttx-ci-linux@sha256:8c4e00b607d4d6d66ba8f51c4544819a616eac69d3a2ac669e2af2150e2eb0f9 build_llvm_libraries_xtensa: + permissions: + contents: read + actions: write uses: ./.github/workflows/build_llvm_libraries.yml with: os: "ubuntu-22.04" @@ -74,11 +83,11 @@ jobs: target: "riscv32", fpu_type: "none" }, - { - config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh", - target: "riscv32_ilp32f", - fpu_type: "fp" - }, + #{ + # config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh", + # target: "riscv32_ilp32f", + # fpu_type: "fp" + #}, # { # config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh", # target: "riscv32_ilp32d", @@ -327,19 +336,6 @@ jobs: working-directory: apps/interpreters/wamr/wamr - name: Test - if: matrix.target_config.target != 'xtensa' - run: | - cd apps/interpreters/wamr/wamr/tests/wamr-test-suites - ./test_wamr.sh -s spec ${{ matrix.wamr_test_option.mode }} -m ${{ matrix.target_config.target }} -b -Q -P -F ${{ steps.build_firmware_path.outputs.firmware }} ${{ matrix.wamr_feature_option.mode}} - - # for xtensa, for some reasons, when running the tests - # with test_wamr.sh -P, nuttx occasionally hangs after - # "total segments stored 6" on the CI. - # i (yamamoto) couldn't reproduce it locally (macOS) even - # with the identical flash image. - # for now, run the tests without -P. - - name: Test - if: matrix.target_config.target == 'xtensa' run: | cd apps/interpreters/wamr/wamr/tests/wamr-test-suites ./test_wamr.sh -s spec ${{ matrix.wamr_test_option.mode }} -m ${{ matrix.target_config.target }} -b -Q -F ${{ steps.build_firmware_path.outputs.firmware }} ${{ matrix.wamr_feature_option.mode}} @@ -354,7 +350,7 @@ jobs: - name: upload the log if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v4.4.3 with: name: spec-test-log-${{ github.run_id }}-${{ strategy.job-index }}-${{ matrix.target_config.target }} path: log diff --git a/.github/workflows/supply_chain.yml b/.github/workflows/supply_chain.yml new file mode 100644 index 000000000..26ad7d33e --- /dev/null +++ b/.github/workflows/supply_chain.yml @@ -0,0 +1,65 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +# Check current WASM Micro Runtime results here: https://securityscorecards.dev/viewer/?uri=github.com/bytecodealliance/wasm-micro-runtime + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + # midnight UTC + schedule: + - cron: "0 0 * * *" + # allow to be triggered manually + workflow_dispatch: + +# Declare default permissions as read only. +permissions: + contents: read + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + if: github.repository == 'bytecodealliance/wasm-micro-runtime' + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + with: + results_file: results.sarif + results_format: sarif + + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@184d73b71b93c222403b2e7f1ffebe4508014249 # v3.1.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@af56b044b5d41c317aef5d19920b3183cb4fbbec # v2.2.4 + with: + sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index 355d391f1..baf11c891 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ .clangd .DS_Store *.o +.aider* core/deps/** core/shared/mem-alloc/tlsf diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index cba0e5c4b..ce0d4f852 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -60,7 +60,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the ### llvm -[LICENSE](./LICENCE.txt) +[LICENSE](./LICENSE) ### wasm-c-api diff --git a/CMakeLists.txt b/CMakeLists.txt index c7f766689..40658e9ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,10 +121,15 @@ set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow -Wno-unused-parameter -fvisibility=hidden") -# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") - -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused") +if (NOT WIN32) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security \ + -ffunction-sections -fdata-sections \ + -Wno-unused-parameter -Wno-pedantic \ + -fvisibility=hidden") + # Remove the extra spaces for better make log + string (REGEX REPLACE " *" " " CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused") +endif() if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) @@ -145,6 +150,10 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) set (THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) +if (MSVC) + add_definitions(-DCOMPILING_WASM_RUNTIME_API=1) +endif () + # STATIC LIBRARY if (WAMR_BUILD_STATIC) add_library(iwasm_static STATIC ${WAMR_RUNTIME_LIB_SOURCE}) @@ -155,6 +164,14 @@ if (WAMR_BUILD_STATIC) target_link_libraries(iwasm_static INTERFACE boringssl_crypto) endif () + if (MINGW) + target_link_libraries (iwasm_static PRIVATE ws2_32) + endif () + + if (WIN32) + target_link_libraries(iwasm_static PRIVATE ntdll) + endif() + install (TARGETS iwasm_static ARCHIVE DESTINATION lib) endif () @@ -169,9 +186,14 @@ if (WAMR_BUILD_SHARED) endif () if (MINGW) - target_link_libraries (iwasm_shared INTERFACE -lWs2_32 -lwsock32) + target_link_libraries(iwasm_shared INTERFACE -lWs2_32 -lwsock32) + target_link_libraries(iwasm_shared PRIVATE ws2_32) endif () + if (WIN32) + target_link_libraries(iwasm_shared PRIVATE ntdll) + endif() + install (TARGETS iwasm_shared LIBRARY DESTINATION lib) endif () diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..d8ec4c1b3 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,29 @@ +# In this project, we use CODEOWNERS to identify people who are likely to know +# who should review a pull request. +# +# People listed in this file are committing to respond in a timely fashion to +# PRs in the selected areas. However, that response doesn't have to be a full +# code review; it could also take any of these forms: +# +# - "I intend to review this but I can't yet. Please leave me a message if I +# haven't responded by (a specific date in the near future)." +# +# - "I think (a specific other contributor) should review this." (Note that the +# best reviewer for a PR may not necessarily be listed in this file.) +# +# People must only be added to this file if they've agreed to provide one of +# the above responses in a reasonable amount of time for every PR to which +# they're assigned. +# +# We only ask for this commitment from people who are employed full-time to +# work on this project. We gratefully welcome reviews from other contributors, +# but we don't believe it's fair to ask volunteers to respond quickly. + +# If none of the later patterns match, assign to anyone. This team is the +# parent of all the other teams and automatically includes everyone on those +# teams. +* @loganek @lum1n0us @no1wudi @wenyongh @xujuntwt95329 @yamt + +# Some parts of the project require more specialized knowledge. In those areas +# we designate smaller groups who are more likely to be aware of who's working +# in specific areas. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e296cdf9e..e0bb032cf 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,85 @@ +## WAMR-2.2.0 + +### Breaking changes + +### New features +- Add support for multi-memory proposal in classic interpreter (#3742) +- wasi-nn: Add a new target for llama.cpp as a wasi-nn backend (#3709) +- Add memory instance support apis (#3786) +- Implement a first version of shared heap feature (#3789) +- Support dynamic aot debug (#3788) +- Implement shared heap for AOT (#3815) +- Support table64 extension in classic-interp and AOT running modes (#3811) + + +### Bug fixes +- Enable merged os_mmap for aot data sections (#3681) +- Fix arm64 issues on mac (#3688) +- aot loader: Call os_mmap with MMAP_MAP_32BIT only when target is x86-64 or riscv64 (#3755) +- Fix building iwasm_shared and iwasm_static libs on win32 (#3762) +- Fix compile error when multi-module and tags are enabled (#3781) +- Fix aot multi export memory support (#3791) +- Fix Windows compile error when uvwasi is enabled (#3810) +- Fix missing symbols when using aot mode on riscv platforms (#3812) +- Fix mac build of libc_emcc_wrapper.c (#3836) +- aot_comp_option.h: Add missing stdint.h header (#3834) +- Fix compilation error found in tflite test (#3820) +- Fix exec_env_tls assertion in module instantiation (#3844) +- Fix issues of destroy_shared_heaps (#3847) + +### Enhancements +- aot loader: Refine os_mmap related code (#3711) +- Enable merged os_mmap for aot data sections and aot text (#3743) +- Improve posix mmap retry logic (#3714) +- Remove unnecessary code duplication in aot runtime (#3767) +- Add wamrc parameter to configure stack frame features (#3763) +- refactoring: Re-use commit IP functionality between exception handling and other cases (#3768) +- AOT call stack optimizations (#3773) +- Appease GCC strict prototypes warning (#3775) +- Appease GCC -Wformat (#3783) +- Fix compiler warnings (#3784) +- Implement option for skipping function index in the callstack (#3785) +- Fix a compile warning in aot_emit_function.c (#3793) +- Restore cmake hidden compile symbol visibility (#3796) +- Refactor shared heap feature for interpreter mode (#3794) +- Add no_resolve to LoadArgs and wasm_runtime_resolve_symbols (#3790) +- shared heap: Fix some issues and add basic unit test case (#3801) +- Add shared heap sample (#3806) +- Fix unused param warning when GC is enabled (#3814) +- Add scoreboard CI for supply-chain security (#3819) +- Emit load_addr and load_size if WAMR_ENABLE_COMPILER is set (#3835) +- libc-emcc: Use alternate method to check getrandom support (#3848) +- Enable libc-wasi for windows msvc build (#3852) +- Remove unused folder samples/gui and samples/littlevgl (#3853) +- Fix some compile warnings and typos (#3854) +- Allow to set native stack boundary to exec_env (#3862) +- Refine wasm/aot function instance lookup (#3865) +- Fix quadratic runtime for duplicate export name detection (#3861) + + +### Others +- Add a comment on AOT_SECTION_TYPE_SIGNATURE (#3746) +- CI: Freeze version of bloaty for NuttX compilation (#3756) +- aot compiler: Allow to control stack boundary check when boundary check is enabled (#3754) +- Update ref to the multi-memory tests (#3764) +- compilation_on_nuttx.yml: Update checkout action to suppress warnings (#3765) +- CI: Disable parallel test in spectest for NuttX (#3780) +- spec_test_on_nuttx.yml: Disable riscv32_ilp32f for now (#3777) +- Ignore temporary file from aider (#3787) +- Add CODEOWNERS (#3822) +- build(deps): bump github/codeql-action from 2.2.4 to 3.26.9 (#3826) +- build(deps): bump actions/upload-artifact from 3.1.0 to 4.4.0 (#3827) +- build(deps): bump ossf/scorecard-action from 2.3.1 to 2.4.0 (#3828) +- build(deps): bump github/codeql-action from 3.26.9 to 3.26.11 (#3843) +- build(deps): bump actions/upload-artifact from 4.4.0 to 4.4.3 (#3855) +- build(deps): bump github/codeql-action from 3.26.11 to 3.26.12 (#3856) +- Add Windows wamrc and iwasm build in release CI (#3857) +- Fix syntax error in codeql_buildscript.sh (#3864) +- release CI: Add another iwasm binary that supports Garbage Collection and Exception Handling (#3866) +- Fix lookup function issue reported in nightly run (#3868) + +--- + ## WAMR-2.1.2 ### Breaking Changes diff --git a/build-scripts/build_llvm.py b/build-scripts/build_llvm.py index 40765d0fe..7de55b6a0 100755 --- a/build-scripts/build_llvm.py +++ b/build-scripts/build_llvm.py @@ -125,9 +125,7 @@ def build_llvm(llvm_dir, platform, backends, projects, use_clang=False, extra_fl if not llvm_dir.exists(): raise Exception(f"{llvm_dir} doesn't exist") - build_dir = llvm_dir.joinpath( - "win32build" if "windows" == platform else "build" - ).resolve() + build_dir = llvm_dir.joinpath("build").resolve() build_dir.mkdir(exist_ok=True) lib_llvm_core_library = build_dir.joinpath("lib/libLLVMCore.a").resolve() @@ -178,6 +176,7 @@ def repackage_llvm(llvm_dir): raise Exception("Find more than one LLVM-*.tar.gz") if not packs: + raise Exception("Didn't find any LLVM-* package") return llvm_package = packs[0].name @@ -193,6 +192,31 @@ def repackage_llvm(llvm_dir): # rm ./LLVM-1*.gz os.remove(llvm_dir.joinpath(llvm_package).resolve()) +def repackage_llvm_windows(llvm_dir): + build_dir = llvm_dir.joinpath("./build").resolve() + + packs_path = [f for f in build_dir.glob("./_CPack_Packages/win64/NSIS/LLVM-*-win64")] + if len(packs_path) > 1: + raise Exception("Find more than one LLVM-* package") + + if not packs_path: + raise Exception("Didn't find any LLVM-* package") + return + + llvm_package_path = f"_CPack_Packages/win64/NSIS/{packs_path[0].name}" + windows_package_dir = build_dir.joinpath(llvm_package_path).resolve() + + # mv package dir outside of build + shutil.move(str(windows_package_dir), str(llvm_dir)) + # rm -r build + shutil.rmtree(str(build_dir)) + # mkdir build + build_dir.mkdir() + # move back all the subdiretories under cpack directory(bin/include/lib) to build dir + moved_package_dir = llvm_dir.joinpath(packs_path[0].name) + for sub_dir in moved_package_dir.iterdir(): + shutil.move(str(sub_dir), str(build_dir)) + moved_package_dir.rmdir() def main(): parser = argparse.ArgumentParser(description="build necessary LLVM libraries") @@ -304,7 +328,11 @@ def main(): ) is not None ): - repackage_llvm(llvm_dir) + # TODO: repackage process may change in the future, this work for LLVM 15.x + if "windows" == platform: + repackage_llvm_windows(llvm_dir) + else: + repackage_llvm(llvm_dir) return True except subprocess.CalledProcessError: diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 252ba3a84..48c5f7be4 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -102,9 +102,6 @@ if (WAMR_BUILD_JIT EQUAL 1) if (NOT DEFINED LLVM_DIR) set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/build") - if (WAMR_BUILD_PLATFORM STREQUAL "windows") - set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/win32build") - endif () if (NOT EXISTS "${LLVM_BUILD_ROOT}") message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_BUILD_ROOT}") endif () @@ -256,6 +253,11 @@ if (WAMR_BUILD_SHARED_MEMORY EQUAL 1) else () add_definitions (-DWASM_ENABLE_SHARED_MEMORY=0) endif () +if (WAMR_BUILD_SHARED_HEAP EQUAL 1) + add_definitions (-DWASM_ENABLE_SHARED_HEAP=1) + message (" Shared heap enabled") +endif() + if (WAMR_BUILD_MEMORY64 EQUAL 1) # if native is 32-bit or cross-compiled to 32-bit if (NOT WAMR_BUILD_TARGET MATCHES ".*64.*") @@ -404,6 +406,10 @@ endif () if (WAMR_BUILD_DEBUG_AOT EQUAL 1) message (" Debug AOT enabled") endif () +if (WAMR_BUILD_DYNAMIC_AOT_DEBUG EQUAL 1) + add_definitions (-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1) + message (" Dynamic AOT debug enabled") +endif () if (WAMR_BUILD_LOAD_CUSTOM_SECTION EQUAL 1) add_definitions (-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1) message (" Load custom section enabled") @@ -442,7 +448,9 @@ if (WAMR_BUILD_WASI_NN EQUAL 1) message (" WASI-NN enabled") add_definitions (-DWASM_ENABLE_WASI_NN=1) # Variant backends - if (NOT WAMR_BUILD_WASI_NN_TFLITE EQUAL 1 AND NOT WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1) + if (NOT WAMR_BUILD_WASI_NN_TFLITE EQUAL 1 AND + NOT WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1 AND + NOT WAMR_BUILD_WASI_NN_LLAMACPP EQUAL 1) message (FATAL_ERROR " Need to select a backend for WASI-NN") endif () @@ -454,6 +462,10 @@ if (WAMR_BUILD_WASI_NN EQUAL 1) message (" WASI-NN: backend openvino enabled") add_definitions (-DWASM_ENABLE_WASI_NN_OPENVINO) endif () + if (WAMR_BUILD_WASI_NN_LLAMACPP EQUAL 1) + message (" WASI-NN: backend llamacpp enabled") + add_definitions (-DWASM_ENABLE_WASI_NN_LLAMACPP) + endif () # Variant devices if (WAMR_BUILD_WASI_NN_ENABLE_GPU EQUAL 1) message (" WASI-NN: GPU enabled") @@ -483,7 +495,7 @@ if (WAMR_BUILD_MODULE_INST_CONTEXT EQUAL 1) message (" Module instance context enabled") endif () if (WAMR_BUILD_GC_HEAP_VERIFY EQUAL 1) - add_definitions (-DWASM_ENABLE_GC_VERIFY=1) + add_definitions (-DBH_ENABLE_GC_VERIFY=1) message (" GC heap verification enabled") endif () if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 3ab0cff4f..c57cfc57a 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -59,7 +59,12 @@ if (WAMR_BUILD_INTERP EQUAL 1) endif () if (WAMR_BUILD_FAST_JIT EQUAL 1) - include (${IWASM_DIR}/fast-jit/iwasm_fast_jit.cmake) + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + message ("Fast JIT currently not supported on Windows") + set (WAMR_BUILD_FAST_JIT 0) + else () + include (${IWASM_DIR}/fast-jit/iwasm_fast_jit.cmake) + endif () endif () if (WAMR_BUILD_JIT EQUAL 1) @@ -104,6 +109,10 @@ if (WAMR_BUILD_WASI_NN EQUAL 1) endif () if (WAMR_BUILD_LIB_PTHREAD EQUAL 1) + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + set (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE 0) + message ("Lib pthread semaphore currently not supported on Windows") + endif () include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake) # Enable the dependent feature if lib pthread is enabled set (WAMR_BUILD_THREAD_MGR 1) @@ -119,6 +128,10 @@ if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1) set (WAMR_BUILD_SHARED_MEMORY 1) endif () +if (WAMR_BUILD_SHARED_HEAP EQUAL 1) + include (${IWASM_DIR}/libraries/shared-heap/shared_heap.cmake) +endif () + if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_THREAD_MGR 1) include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake) @@ -193,6 +206,7 @@ set (source_all ${LIBC_EMCC_SOURCE} ${LIB_RATS_SOURCE} ${DEBUG_ENGINE_SOURCE} + ${LIB_SHARED_HEAP_SOURCE} ) set (WAMR_RUNTIME_LIB_SOURCE ${source_all}) diff --git a/ci/coding_guidelines_check.py b/ci/coding_guidelines_check.py index d96446266..a0b4535f9 100644 --- a/ci/coding_guidelines_check.py +++ b/ci/coding_guidelines_check.py @@ -180,6 +180,7 @@ def check_file_name(path: Path) -> bool: "docker-compose", "package-lock", "vite-env.d", + "osv-scanner", ]: return True diff --git a/core/config.h b/core/config.h index a25eb543e..6bab4da90 100644 --- a/core/config.h +++ b/core/config.h @@ -75,6 +75,10 @@ #define WASM_ENABLE_AOT 0 #endif +#ifndef WASM_ENABLE_DYNAMIC_AOT_DEBUG +#define WASM_ENABLE_DYNAMIC_AOT_DEBUG 0 +#endif + #ifndef WASM_ENABLE_WORD_ALIGN_READ #define WASM_ENABLE_WORD_ALIGN_READ 0 #endif @@ -392,7 +396,9 @@ #define APP_HEAP_SIZE_DEFAULT (8 * 1024) #endif #define APP_HEAP_SIZE_MIN (256) -#define APP_HEAP_SIZE_MAX (512 * 1024 * 1024) +/* The ems memory allocator supports maximal heap size 1GB, + see ems_gc_internal.h */ +#define APP_HEAP_SIZE_MAX (1024 * 1024 * 1024) /* Default min/max gc heap size of each app */ #ifndef GC_HEAP_SIZE_DEFAULT @@ -688,4 +694,8 @@ #endif #endif /* WASM_ENABLE_FUZZ_TEST != 0 */ +#ifndef WASM_ENABLE_SHARED_HEAP +#define WASM_ENABLE_SHARED_HEAP 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index b96079d3b..01e246aa3 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -4,9 +4,8 @@ */ #include "aot_runtime.h" -#include "bh_common.h" -#include "bh_log.h" #include "aot_reloc.h" +#include "bh_platform.h" #include "../common/wasm_runtime_common.h" #include "../common/wasm_native.h" #include "../common/wasm_loader_common.h" @@ -302,7 +301,10 @@ loader_mmap(uint32 size, bool prot_exec, char *error_buf, uint32 error_buf_size) int map_flags; void *mem; -#if UINTPTR_MAX == UINT64_MAX +#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) +#ifndef __APPLE__ /* The mmapped AOT data and code in 64-bit targets had better be in range 0 to 2G, or aot loader may fail to apply some relocations, e.g., R_X86_64_32/R_X86_64_32S/R_X86_64_PC32/R_RISCV_32. @@ -316,6 +318,7 @@ loader_mmap(uint32 size, bool prot_exec, char *error_buf, uint32 error_buf_size) bh_assert((uintptr_t)mem < INT32_MAX); return mem; } +#endif #endif map_flags = MMAP_MAP_NONE; @@ -579,6 +582,10 @@ load_target_info_section(const uint8 *buf, const uint8 *buf_end, return false; } + /* for backwards compatibility with previous wamrc aot files */ + if (!strcmp(target_info.arch, "arm64")) + bh_strcpy_s(target_info.arch, sizeof(target_info.arch), "aarch64v8"); + /* Check machine info */ if (!check_machine_info(&target_info, error_buf, error_buf_size)) { return false; @@ -589,6 +596,10 @@ load_target_info_section(const uint8 *buf, const uint8 *buf_end, return false; } +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + module->feature_flags = target_info.feature_flags; +#endif + /* Finally, check feature flags */ return check_feature_flags(error_buf, error_buf_size, target_info.feature_flags); @@ -622,73 +633,6 @@ str2uint32(const char *buf, uint32 *p_res); static bool str2uint64(const char *buf, uint64 *p_res); -#if WASM_ENABLE_MULTI_MODULE != 0 -static void * -aot_loader_resolve_function(const AOTModule *module, const char *function_name, - const AOTFuncType *expected_function_type, - char *error_buf, uint32 error_buf_size); - -static void * -aot_loader_resolve_function_ex(const char *module_name, - const char *function_name, - const AOTFuncType *expected_function_type, - char *error_buf, uint32 error_buf_size) -{ - WASMModuleCommon *module_reg; - - module_reg = wasm_runtime_find_module_registered(module_name); - if (!module_reg || module_reg->module_type != Wasm_Module_AoT) { - LOG_DEBUG("can not find a module named %s for function %s", module_name, - function_name); - set_error_buf(error_buf, error_buf_size, "unknown import"); - return NULL; - } - return aot_loader_resolve_function((AOTModule *)module_reg, function_name, - expected_function_type, error_buf, - error_buf_size); -} - -static void * -aot_loader_resolve_function(const AOTModule *module, const char *function_name, - const AOTFuncType *expected_function_type, - char *error_buf, uint32 error_buf_size) -{ - void *function = NULL; - AOTExport *export = NULL; - AOTFuncType *target_function_type = NULL; - - export = loader_find_export((WASMModuleCommon *)module, module->name, - function_name, EXPORT_KIND_FUNC, error_buf, - error_buf_size); - if (!export) { - return NULL; - } - - /* resolve function type and function */ - if (export->index < module->import_func_count) { - target_function_type = module->import_funcs[export->index].func_type; - function = module->import_funcs[export->index].func_ptr_linked; - } - else { - target_function_type = - (AOTFuncType *)module - ->types[module->func_type_indexes[export->index - - module->import_func_count]]; - function = - (module->func_ptrs[export->index - module->import_func_count]); - } - /* check function type */ - if (!wasm_type_equal((WASMType *)expected_function_type, - (WASMType *)target_function_type, module->types, - module->type_count)) { - LOG_DEBUG("%s.%s failed the type check", module->name, function_name); - set_error_buf(error_buf, error_buf_size, "incompatible import type"); - return NULL; - } - return function; -} -#endif /* end of WASM_ENABLE_MULTI_MODULE */ - static bool load_native_symbol_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module, bool is_load_from_file_buf, @@ -1437,6 +1381,12 @@ load_table_list(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, for (i = 0; i < module->table_count; i++, table++) { read_uint8(buf, buf_end, table->table_type.elem_type); read_uint8(buf, buf_end, table->table_type.flags); + + if (!wasm_table_check_flags(table->table_type.flags, error_buf, + error_buf_size, true)) { + return false; + } + read_uint8(buf, buf_end, table->table_type.possible_grow); #if WASM_ENABLE_GC != 0 if (wasm_is_type_multi_byte_type(table->table_type.elem_type)) { @@ -2273,19 +2223,13 @@ destroy_import_funcs(AOTImportFunc *import_funcs) static bool load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, - bool is_load_from_file_buf, char *error_buf, + bool is_load_from_file_buf, bool no_resolve, char *error_buf, uint32 error_buf_size) { - char *module_name, *field_name; const uint8 *buf = *p_buf; AOTImportFunc *import_funcs; uint64 size; uint32 i; -#if WASM_ENABLE_MULTI_MODULE != 0 - AOTModule *sub_module = NULL; - AOTFunc *linked_func = NULL; - AOTFuncType *declare_func_type = NULL; -#endif /* Allocate memory */ size = sizeof(AOTImportFunc) * (uint64)module->import_func_count; @@ -2302,53 +2246,17 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, return false; } -#if WASM_ENABLE_MULTI_MODULE != 0 - declare_func_type = - (AOTFuncType *)module->types[import_funcs[i].func_type_index]; - read_string(buf, buf_end, module_name); - read_string(buf, buf_end, field_name); - - import_funcs[i].module_name = module_name; - import_funcs[i].func_name = field_name; - linked_func = wasm_native_resolve_symbol( - module_name, field_name, declare_func_type, - &import_funcs[i].signature, &import_funcs[i].attachment, - &import_funcs[i].call_conv_raw); - if (!linked_func) { - sub_module = NULL; - if (!wasm_runtime_is_built_in_module(module_name)) { - sub_module = (AOTModule *)wasm_runtime_load_depended_module( - (WASMModuleCommon *)module, module_name, error_buf, - error_buf_size); - if (!sub_module) { - LOG_ERROR("failed to load sub module: %s", error_buf); - return false; - } - } - if (!sub_module) - linked_func = aot_loader_resolve_function_ex( - module_name, field_name, declare_func_type, error_buf, - error_buf_size); - else - linked_func = aot_loader_resolve_function( - sub_module, field_name, declare_func_type, error_buf, - error_buf_size); - } - import_funcs[i].func_ptr_linked = linked_func; - import_funcs[i].func_type = declare_func_type; - -#else import_funcs[i].func_type = (AOTFuncType *)module->types[import_funcs[i].func_type_index]; read_string(buf, buf_end, import_funcs[i].module_name); read_string(buf, buf_end, import_funcs[i].func_name); - module_name = import_funcs[i].module_name; - field_name = import_funcs[i].func_name; - import_funcs[i].func_ptr_linked = wasm_native_resolve_symbol( - module_name, field_name, import_funcs[i].func_type, - &import_funcs[i].signature, &import_funcs[i].attachment, - &import_funcs[i].call_conv_raw); -#endif + import_funcs[i].attachment = NULL; + import_funcs[i].signature = NULL; + import_funcs[i].call_conv_raw = false; + + if (!no_resolve) { + aot_resolve_import_func(module, &import_funcs[i]); + } #if WASM_ENABLE_LIBC_WASI != 0 if (!strcmp(import_funcs[i].module_name, "wasi_unstable") @@ -2366,7 +2274,7 @@ fail: static bool load_import_func_info(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, bool is_load_from_file_buf, - char *error_buf, uint32 error_buf_size) + bool no_resolve, char *error_buf, uint32 error_buf_size) { const uint8 *buf = *p_buf; @@ -2375,7 +2283,7 @@ load_import_func_info(const uint8 **p_buf, const uint8 *buf_end, /* load import funcs */ if (module->import_func_count > 0 && !load_import_funcs(&buf, buf_end, module, is_load_from_file_buf, - error_buf, error_buf_size)) + no_resolve, error_buf, error_buf_size)) return false; *p_buf = buf; @@ -2502,7 +2410,7 @@ fail: static bool load_init_data_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module, bool is_load_from_file_buf, - char *error_buf, uint32 error_buf_size) + bool no_resolve, char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; @@ -2513,7 +2421,7 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end, error_buf, error_buf_size) || !load_global_info(&p, p_end, module, error_buf, error_buf_size) || !load_import_func_info(&p, p_end, module, is_load_from_file_buf, - error_buf, error_buf_size)) + no_resolve, error_buf, error_buf_size)) return false; /* load function count and start function index */ @@ -2603,6 +2511,15 @@ try_merge_data_and_text(const uint8 **buf, const uint8 **buf_end, /* merge failed but may be not critical for some targets */ return false; } + +#ifdef BH_PLATFORM_WINDOWS + if (!os_mem_commit(sections, code_size, + MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC)) { + os_munmap(sections, (uint32)total_size); + return false; + } +#endif + /* change the code part to be executable */ if (os_mprotect(sections, code_size, MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC) @@ -2617,7 +2534,7 @@ try_merge_data_and_text(const uint8 **buf, const uint8 **buf_end, /* order not essential just as compiler does: .text section first */ *buf = sections; *buf_end = sections + code_size; - bh_memcpy_s(sections, code_size, old_buf, code_size); + bh_memcpy_s(sections, (uint32)code_size, old_buf, (uint32)code_size); os_munmap(old_buf, code_size); sections += align_uint((uint32)code_size, page_size); @@ -2835,6 +2752,48 @@ destroy_exports(AOTExport *exports) wasm_runtime_free(exports); } +static int +cmp_export_name(const void *a, const void *b) +{ + return strcmp(*(char **)a, *(char **)b); +} + +static bool +check_duplicate_exports(AOTModule *module, char *error_buf, + uint32 error_buf_size) +{ + uint32 i; + bool result = false; + char *names_buf[32], **names = names_buf; + if (module->export_count > 32) { + names = loader_malloc(module->export_count * sizeof(char *), error_buf, + error_buf_size); + if (!names) { + return result; + } + } + + for (i = 0; i < module->export_count; i++) { + names[i] = module->exports[i].name; + } + + qsort(names, module->export_count, sizeof(char *), cmp_export_name); + + for (i = 1; i < module->export_count; i++) { + if (!strcmp(names[i], names[i - 1])) { + set_error_buf(error_buf, error_buf_size, "duplicate export name"); + goto cleanup; + } + } + + result = true; +cleanup: + if (module->export_count > 32) { + wasm_runtime_free(names); + } + return result; +} + static bool load_exports(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, bool is_load_from_file_buf, char *error_buf, uint32 error_buf_size) @@ -2856,14 +2815,58 @@ load_exports(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, read_uint32(buf, buf_end, exports[i].index); read_uint8(buf, buf_end, exports[i].kind); read_string(buf, buf_end, exports[i].name); -#if 0 /* TODO: check kind and index */ - if (export_funcs[i].index >= - module->func_count + module->import_func_count) { - set_error_buf(error_buf, error_buf_size, - "function index is out of range"); + + /* Check export kind and index */ + switch (exports[i].kind) { + case EXPORT_KIND_FUNC: + if (exports[i].index + >= module->import_func_count + module->func_count) { + set_error_buf(error_buf, error_buf_size, + "unknown function"); + return false; + } + break; + case EXPORT_KIND_TABLE: + if (exports[i].index + >= module->import_table_count + module->table_count) { + set_error_buf(error_buf, error_buf_size, "unknown table"); + return false; + } + break; + case EXPORT_KIND_MEMORY: + if (exports[i].index + >= module->import_memory_count + module->memory_count) { + set_error_buf(error_buf, error_buf_size, "unknown memory"); + return false; + } + break; + case EXPORT_KIND_GLOBAL: + if (exports[i].index + >= module->import_global_count + module->global_count) { + set_error_buf(error_buf, error_buf_size, "unknown global"); + return false; + } + break; +#if WASM_ENABLE_TAGS != 0 + /* TODO + case EXPORT_KIND_TAG: + if (index >= module->import_tag_count + module->tag_count) { + set_error_buf(error_buf, error_buf_size, "unknown tag"); + return false; + } + break; + */ +#endif + default: + set_error_buf(error_buf, error_buf_size, "invalid export kind"); + return false; + } + } + + if (module->export_count > 0) { + if (!check_duplicate_exports(module, error_buf, error_buf_size)) { return false; } -#endif } *p_buf = buf; @@ -3807,7 +3810,7 @@ has_module_memory64(AOTModule *module) static bool load_from_sections(AOTModule *module, AOTSection *sections, - bool is_load_from_file_buf, char *error_buf, + bool is_load_from_file_buf, bool no_resolve, char *error_buf, uint32 error_buf_size) { AOTSection *section = sections; @@ -3840,8 +3843,8 @@ load_from_sections(AOTModule *module, AOTSection *sections, break; case AOT_SECTION_TYPE_INIT_DATA: if (!load_init_data_section(buf, buf_end, module, - is_load_from_file_buf, error_buf, - error_buf_size)) + is_load_from_file_buf, no_resolve, + error_buf, error_buf_size)) return false; break; case AOT_SECTION_TYPE_TEXT: @@ -4064,7 +4067,7 @@ aot_load_from_sections(AOTSection *section_list, char *error_buf, if (!module) return NULL; - if (!load_from_sections(module, section_list, false, error_buf, + if (!load_from_sections(module, section_list, false, false, error_buf, error_buf_size)) { aot_unload(module); return NULL; @@ -4234,7 +4237,8 @@ fail: static bool load(const uint8 *buf, uint32 size, AOTModule *module, - bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size) + bool wasm_binary_freeable, bool no_resolve, char *error_buf, + uint32 error_buf_size) { const uint8 *buf_end = buf + size; const uint8 *p = buf, *p_end = buf_end; @@ -4261,7 +4265,7 @@ load(const uint8 *buf, uint32 size, AOTModule *module, return false; ret = load_from_sections(module, section_list, !wasm_binary_freeable, - error_buf, error_buf_size); + no_resolve, error_buf, error_buf_size); if (!ret) { /* If load_from_sections() fails, then aot text is destroyed in destroy_sections() */ @@ -4309,8 +4313,8 @@ aot_load_from_aot_file(const uint8 *buf, uint32 size, const LoadArgs *args, return NULL; os_thread_jit_write_protect_np(false); /* Make memory writable */ - if (!load(buf, size, module, args->wasm_binary_freeable, error_buf, - error_buf_size)) { + if (!load(buf, size, module, args->wasm_binary_freeable, args->no_resolve, + error_buf, error_buf_size)) { aot_unload(module); return NULL; } diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index 8ead3cd93..f7ada4d8d 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -226,7 +226,7 @@ SymbolMap * get_target_symbol_map(uint32 *sym_num); uint32 -get_plt_table_size(); +get_plt_table_size(void); void init_plt_table(uint8 *plt); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 3ca26114f..7e6d6360c 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -4,6 +4,7 @@ */ #include "aot_runtime.h" +#include "../compilation/aot_stack_frame.h" #include "bh_log.h" #include "mem_alloc.h" #include "../common/wasm_runtime_common.h" @@ -56,6 +57,9 @@ bh_static_assert(sizeof(AOTMemoryInstance) == 120); bh_static_assert(offsetof(AOTTableInstance, elems) == 24); bh_static_assert(offsetof(AOTModuleInstanceExtra, stack_sizes) == 0); +bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj) + == 8); +bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_start_off) == 16); bh_static_assert(sizeof(CApiFuncImport) == sizeof(uintptr_t) * 3); @@ -72,6 +76,10 @@ bh_static_assert(offsetof(AOTFrame, sp) == sizeof(uintptr_t) * 5); bh_static_assert(offsetof(AOTFrame, frame_ref) == sizeof(uintptr_t) * 6); bh_static_assert(offsetof(AOTFrame, lp) == sizeof(uintptr_t) * 7); +bh_static_assert(offsetof(AOTTinyFrame, func_index) == sizeof(uint32) * 0); +bh_static_assert(offsetof(AOTTinyFrame, ip_offset) == sizeof(uint32) * 1); +bh_static_assert(sizeof(AOTTinyFrame) == sizeof(uint32) * 2); + static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) { @@ -110,6 +118,66 @@ runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) return mem; } +#if WASM_ENABLE_AOT_STACK_FRAME != 0 +static bool +is_tiny_frame(WASMExecEnv *exec_env) +{ + AOTModule *module = + (AOTModule *)((AOTModuleInstance *)exec_env->module_inst)->module; + + return module->feature_flags & WASM_FEATURE_TINY_STACK_FRAME; +} + +static bool +is_frame_per_function(WASMExecEnv *exec_env) +{ + AOTModule *module = + (AOTModule *)((AOTModuleInstance *)exec_env->module_inst)->module; + + return module->feature_flags & WASM_FEATURE_FRAME_PER_FUNCTION; +} + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +static bool +is_frame_func_idx_disabled(WASMExecEnv *exec_env) +{ + AOTModule *module = + (AOTModule *)((AOTModuleInstance *)exec_env->module_inst)->module; + + return module->feature_flags & WASM_FEATURE_FRAME_NO_FUNC_IDX; +} +#endif + +static void * +get_top_frame(WASMExecEnv *exec_env) +{ + if (is_tiny_frame(exec_env)) { + return exec_env->wasm_stack.top > exec_env->wasm_stack.bottom + ? exec_env->wasm_stack.top - sizeof(AOTTinyFrame) + : NULL; + } + else { + return exec_env->cur_frame; + } +} + +static void * +get_prev_frame(WASMExecEnv *exec_env, void *cur_frame) +{ + bh_assert(cur_frame); + + if (is_tiny_frame(exec_env)) { + if ((uint8 *)cur_frame == exec_env->wasm_stack.bottom) { + return NULL; + } + return ((AOTTinyFrame *)cur_frame) - 1; + } + else { + return ((AOTFrame *)cur_frame)->prev_frame; + } +} +#endif + static bool check_global_init_expr(const AOTModule *module, uint32 global_index, char *error_buf, uint32 error_buf_size) @@ -674,18 +742,24 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module, #if WASM_ENABLE_REF_TYPES != 0 bh_assert( - table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + table_seg->offset.init_expr_type + == (tbl_inst->is_table64 ? INIT_EXPR_TYPE_I64_CONST + : INIT_EXPR_TYPE_I32_CONST) || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST); #else - bh_assert(table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + bh_assert(table_seg->offset.init_expr_type + == (tbl_inst->is_table64 ? INIT_EXPR_TYPE_I64_CONST + : INIT_EXPR_TYPE_I32_CONST) || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL); #endif /* Resolve table data base offset */ + /* TODO: The table64 current implementation assumes table max size + * UINT32_MAX, so the offset conversion here is safe */ if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { global_index = table_seg->offset.u.global_index; @@ -995,7 +1069,24 @@ fail1: return NULL; } -static AOTMemoryInstance * +AOTMemoryInstance * +aot_lookup_memory(AOTModuleInstance *module_inst, char const *name) +{ +#if WASM_ENABLE_MULTI_MEMORY != 0 + uint32 i; + for (i = 0; i < module_inst->export_memory_count; i++) + if (!strcmp(module_inst->export_memories[i].name, name)) + return module_inst->export_memories[i].memory; + return NULL; +#else + (void)module_inst->export_memories; + if (!module_inst->memories) + return NULL; + return module_inst->memories[0]; +#endif +} + +AOTMemoryInstance * aot_get_default_memory(AOTModuleInstance *module_inst) { if (module_inst->memories) @@ -1004,6 +1095,14 @@ aot_get_default_memory(AOTModuleInstance *module_inst) return NULL; } +AOTMemoryInstance * +aot_get_memory_with_index(AOTModuleInstance *module_inst, uint32 index) +{ + if ((index >= module_inst->memory_count) || !module_inst->memories) + return NULL; + return module_inst->memories[index]; +} + static bool memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, AOTModule *module, uint32 heap_size, @@ -1280,6 +1379,15 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module, return true; } +static int +cmp_func_inst(const void *a, const void *b) +{ + const AOTFunctionInstance *func_inst1 = (const AOTFunctionInstance *)a; + const AOTFunctionInstance *func_inst2 = (const AOTFunctionInstance *)b; + + return strcmp(func_inst1->func_name, func_inst2->func_name); +} + static bool create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) @@ -1320,11 +1428,44 @@ create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module, export_func++; } } + + qsort(module_inst->export_functions, module_inst->export_func_count, + sizeof(AOTFunctionInstance), cmp_func_inst); } return true; } +#if WASM_ENABLE_MULTI_MEMORY != 0 +static WASMExportMemInstance * +export_memories_instantiate(const AOTModule *module, + AOTModuleInstance *module_inst, + uint32 export_mem_count, char *error_buf, + uint32 error_buf_size) +{ + WASMExportMemInstance *export_memories, *export_memory; + AOTExport *export = module->exports; + uint32 i; + uint64 total_size = + sizeof(WASMExportMemInstance) * (uint64)export_mem_count; + + if (!(export_memory = export_memories = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return NULL; + } + + for (i = 0; i < module->export_count; i++, export ++) + if (export->kind == EXPORT_KIND_MEMORY) { + export_memory->name = export->name; + export_memory->memory = module_inst->memories[export->index]; + export_memory++; + } + + bh_assert((uint32)(export_memory - export_memories) == export_mem_count); + return export_memories; +} +#endif /* end of if WASM_ENABLE_MULTI_MEMORY != 0 */ + static bool create_exports(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) @@ -1351,6 +1492,17 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module, } } +#if WASM_ENABLE_MULTI_MEMORY != 0 + if (module_inst->export_memory_count) { + module_inst->export_memories = export_memories_instantiate( + module, module_inst, module_inst->export_memory_count, error_buf, + error_buf_size); + if (!module_inst->export_memories) { + return false; + } + } +#endif + return create_export_funcs(module_inst, module, error_buf, error_buf_size); } @@ -1429,8 +1581,12 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst, if (is_sub_inst) { bh_assert(exec_env_main); #ifdef OS_ENABLE_HW_BOUND_CHECK - bh_assert(exec_env_tls == exec_env_main); - (void)exec_env_tls; + /* May come from pthread_create_wrapper, thread_spawn_wrapper and + wasm_cluster_spawn_exec_env. If it comes from the former two, + the exec_env_tls must be not NULL and equal to exec_env_main, + else if it comes from the last one, it may be NULL. */ + if (exec_env_tls) + bh_assert(exec_env_tls == exec_env_main); #endif exec_env = exec_env_main; @@ -1754,6 +1910,24 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, extra->stack_sizes = aot_get_data_section_addr(module, AOT_STACK_SIZES_SECTION_NAME, NULL); + /* + * The AOT code checks whether the n bytes to access are in shared heap + * by checking whether the beginning address meets: + * addr >= start_off && addr <= end_off - n-bytes + 1 + * where n is 1/2/4/8/16 and `end_off - n-bytes + 1` is constant, e.g., + * UINT32_MAX, UINT32_MAX-1, UINT32_MAX-3 for n = 1, 2 or 4 in 32-bit + * target. To simplify the check, when shared heap is disabled, we set + * the start off to UINT64_MAX in 64-bit target and UINT32_MAX in 32-bit + * target, so in the checking, the above formula will be false, we don't + * need to check whether the shared heap is enabled or not in the AOT + * code. + */ +#if UINTPTR_MAX == UINT64_MAX + extra->shared_heap_start_off.u64 = UINT64_MAX; +#else + extra->shared_heap_start_off.u32[0] = UINT32_MAX; +#endif + #if WASM_ENABLE_PERF_PROFILING != 0 total_size = sizeof(AOTFuncPerfProfInfo) * ((uint64)module->import_func_count + module->func_count); @@ -1994,6 +2168,11 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) if (module_inst->export_functions) wasm_runtime_free(module_inst->export_functions); +#if WASM_ENABLE_MULTI_MEMORY != 0 + if (module_inst->export_memories) + wasm_runtime_free(module_inst->export_memories); +#endif + if (extra->functions) { uint32 func_idx; for (func_idx = 0; func_idx < extra->function_count; ++func_idx) { @@ -2039,14 +2218,15 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) AOTFunctionInstance * aot_lookup_function(const AOTModuleInstance *module_inst, const char *name) { - uint32 i; AOTFunctionInstance *export_funcs = (AOTFunctionInstance *)module_inst->export_functions; + AOTFunctionInstance key = { .func_name = (char *)name }; - for (i = 0; i < module_inst->export_func_count; i++) - if (!strcmp(export_funcs[i].func_name, name)) - return &export_funcs[i]; - return NULL; + if (!export_funcs) + return NULL; + + return bsearch(&key, export_funcs, module_inst->export_func_count, + sizeof(AOTFunctionInstance), cmp_func_inst); } #ifdef OS_ENABLE_HW_BOUND_CHECK @@ -2265,7 +2445,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, uint32 ext_ret_cell = wasm_get_cell_num(ext_ret_types, ext_ret_count); uint64 size; #if WASM_ENABLE_AOT_STACK_FRAME != 0 - struct WASMInterpFrame *prev_frame = exec_env->cur_frame; + void *prev_frame = get_top_frame(exec_env); #endif /* Allocate memory all arguments */ @@ -2296,7 +2476,8 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, } #if WASM_ENABLE_AOT_STACK_FRAME != 0 - if (!aot_alloc_frame(exec_env, function->func_index)) { + if (!is_frame_per_function(exec_env) + && !aot_alloc_frame(exec_env, function->func_index)) { if (argv1 != argv1_buf) wasm_runtime_free(argv1); return false; @@ -2324,7 +2505,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, /* Free all frames allocated, note that some frames may be allocated in AOT code and haven't been freed if exception occurred */ - while (exec_env->cur_frame != prev_frame) + while (get_top_frame(exec_env) != prev_frame) aot_free_frame(exec_env); #endif if (!ret) { @@ -2367,9 +2548,12 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, } else { #if WASM_ENABLE_AOT_STACK_FRAME != 0 - struct WASMInterpFrame *prev_frame = exec_env->cur_frame; - - if (!aot_alloc_frame(exec_env, function->func_index)) { + void *prev_frame = get_top_frame(exec_env); + /* Only allocate frame for frame-per-call mode; in the + frame-per-function mode the frame is allocated at the + beginning of the function. */ + if (!is_frame_per_function(exec_env) + && !aot_alloc_frame(exec_env, function->func_index)) { return false; } #endif @@ -2394,7 +2578,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, /* Free all frames allocated, note that some frames may be allocated in AOT code and haven't been freed if exception occurred */ - while (exec_env->cur_frame != prev_frame) + while (get_top_frame(exec_env) != prev_frame) aot_free_frame(exec_env); #endif @@ -2880,7 +3064,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc, goto fail; } #if WASM_ENABLE_AOT_STACK_FRAME != 0 - struct WASMInterpFrame *prev_frame = exec_env->cur_frame; + void *prev_frame = get_top_frame(exec_env); if (!aot_alloc_frame(exec_env, func_idx)) { goto fail; @@ -2894,7 +3078,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc, /* Free all frames allocated, note that some frames may be allocated in AOT code and haven't been freed if exception occurred */ - while (exec_env->cur_frame != prev_frame) + while (get_top_frame(exec_env) != prev_frame) aot_free_frame(exec_env); #endif } @@ -3622,8 +3806,8 @@ get_func_name_from_index(const AOTModuleInstance *module_inst, WASM_ENABLE_PERF_PROFILING != 0 */ #if WASM_ENABLE_GC == 0 -bool -aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index) +static bool +aot_alloc_standard_frame(WASMExecEnv *exec_env, uint32 func_index) { AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; #if WASM_ENABLE_PERF_PROFILING != 0 @@ -3668,37 +3852,10 @@ aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index) return true; } -static inline void -aot_free_frame_internal(WASMExecEnv *exec_env) -{ - AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame; - AOTFrame *prev_frame = cur_frame->prev_frame; - -#if WASM_ENABLE_PERF_PROFILING != 0 - uint64 time_elapsed = - (uintptr_t)os_time_thread_cputime_us() - cur_frame->time_started; - - cur_frame->func_perf_prof_info->total_exec_time += time_elapsed; - cur_frame->func_perf_prof_info->total_exec_cnt++; - - /* parent function */ - if (prev_frame) - prev_frame->func_perf_prof_info->children_exec_time += time_elapsed; -#endif - - exec_env->cur_frame = (struct WASMInterpFrame *)prev_frame; -} - -void -aot_free_frame(WASMExecEnv *exec_env) -{ - aot_free_frame_internal(exec_env); -} - #else /* else of WASM_ENABLE_GC == 0 */ -bool -aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index) +static bool +aot_alloc_standard_frame(WASMExecEnv *exec_env, uint32 func_index) { AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; AOTModule *module = (AOTModule *)module_inst->module; @@ -3752,12 +3909,50 @@ aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index) frame->func_index = func_index; return true; } +#endif /* end of WASM_ENABLE_GC == 0 */ + +static bool +aot_alloc_tiny_frame(WASMExecEnv *exec_env, uint32 func_index) +{ + AOTTinyFrame *new_frame = (AOTTinyFrame *)exec_env->wasm_stack.top; + + if ((uint8 *)new_frame > exec_env->wasm_stack.top_boundary) { + aot_set_exception((WASMModuleInstance *)exec_env->module_inst, + "wasm operand stack overflow"); + return false; + } + + new_frame->func_index = func_index; + exec_env->wasm_stack.top += sizeof(AOTTinyFrame); + return true; +} + +bool +aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index) +{ + AOTModule *module = + (AOTModule *)((AOTModuleInstance *)exec_env->module_inst)->module; + + if (is_frame_per_function(exec_env) + && func_index >= module->import_func_count) { + /* in frame per function mode the frame is allocated at + the beginning of each frame, so we only need to allocate + the frame for imported functions */ + return true; + } + if (is_tiny_frame(exec_env)) { + return aot_alloc_tiny_frame(exec_env, func_index); + } + else { + return aot_alloc_standard_frame(exec_env, func_index); + } +} static inline void -aot_free_frame_internal(WASMExecEnv *exec_env) +aot_free_standard_frame(WASMExecEnv *exec_env) { AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame; - AOTFrame *prev_frame = cur_frame->prev_frame; + AOTFrame *prev_frame = (AOTFrame *)cur_frame->prev_frame; #if WASM_ENABLE_PERF_PROFILING != 0 uint64 time_elapsed = @@ -3771,18 +3966,30 @@ aot_free_frame_internal(WASMExecEnv *exec_env) prev_frame->func_perf_prof_info->children_exec_time += time_elapsed; #endif +#if WASM_ENABLE_GC != 0 wasm_exec_env_free_wasm_frame(exec_env, cur_frame); +#endif exec_env->cur_frame = (struct WASMInterpFrame *)prev_frame; } +static inline void +aot_free_tiny_frame(WASMExecEnv *exec_env) +{ + exec_env->wasm_stack.top = + get_prev_frame(exec_env, exec_env->wasm_stack.top); +} + void aot_free_frame(WASMExecEnv *exec_env) { - aot_free_frame_internal(exec_env); + if (is_tiny_frame(exec_env)) { + aot_free_tiny_frame(exec_env); + } + else { + aot_free_standard_frame(exec_env); + } } -#endif /* end of WASM_ENABLE_GC == 0 */ - void aot_frame_update_profile_info(WASMExecEnv *exec_env, bool alloc_frame) { @@ -3831,14 +4038,13 @@ aot_frame_update_profile_info(WASMExecEnv *exec_env, bool alloc_frame) bool aot_create_call_stack(struct WASMExecEnv *exec_env) { - AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame, - *first_frame = cur_frame; AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; AOTModule *module = (AOTModule *)module_inst->module; uint32 n = 0; - while (cur_frame) { - cur_frame = cur_frame->prev_frame; + void *top_frame = get_top_frame(exec_env); + while (top_frame) { + top_frame = get_prev_frame(exec_env, top_frame); n++; } @@ -3848,31 +4054,53 @@ aot_create_call_stack(struct WASMExecEnv *exec_env) return false; } - cur_frame = first_frame; - while (cur_frame) { + top_frame = get_top_frame(exec_env); + while (n-- > 0) { + uint32 func_index, ip_offset; + uint32 *lp = NULL; +#if WASM_ENABLE_GC != 0 + uint32 *sp = NULL; + uint8 *frame_ref = NULL; +#endif + if (is_tiny_frame(exec_env)) { + AOTTinyFrame *frame = (AOTTinyFrame *)top_frame; + func_index = (uint32)frame->func_index; + ip_offset = (uint32)frame->ip_offset; + } + else { + AOTFrame *frame = (AOTFrame *)top_frame; + func_index = (uint32)frame->func_index; + ip_offset = (uint32)frame->ip_offset; + lp = frame->lp; +#if WASM_ENABLE_GC != 0 + sp = frame->sp; + frame_ref = frame->frame_ref; +#endif + } WASMCApiFrame frame = { 0 }; - uint32 max_local_cell_num, max_stack_cell_num; + uint32 max_local_cell_num = 0, max_stack_cell_num = 0; uint32 all_cell_num, lp_size; frame.instance = module_inst; frame.module_offset = 0; - frame.func_index = (uint32)cur_frame->func_index; - frame.func_offset = (uint32)cur_frame->ip_offset; - frame.func_name_wp = get_func_name_from_index( - module_inst, (uint32)cur_frame->func_index); + frame.func_index = func_index; + frame.func_offset = ip_offset; + frame.func_name_wp = get_func_name_from_index(module_inst, func_index); - if (cur_frame->func_index >= module->import_func_count) { - uint32 aot_func_idx = - (uint32)(cur_frame->func_index - module->import_func_count); - max_local_cell_num = module->max_local_cell_nums[aot_func_idx]; - max_stack_cell_num = module->max_stack_cell_nums[aot_func_idx]; - } - else { - AOTFuncType *func_type = - module->import_funcs[cur_frame->func_index].func_type; - max_local_cell_num = - func_type->param_cell_num > 2 ? func_type->param_cell_num : 2; - max_stack_cell_num = 0; + if (!is_frame_func_idx_disabled(exec_env)) { + if (func_index >= module->import_func_count) { + uint32 aot_func_idx = func_index - module->import_func_count; + max_local_cell_num = module->max_local_cell_nums[aot_func_idx]; + max_stack_cell_num = module->max_stack_cell_nums[aot_func_idx]; + } + else { + AOTFuncType *func_type = + module->import_funcs[func_index].func_type; + max_local_cell_num = func_type->param_cell_num > 2 + ? func_type->param_cell_num + : 2; + max_stack_cell_num = 0; + } } all_cell_num = max_local_cell_num + max_stack_cell_num; @@ -3881,12 +4109,12 @@ aot_create_call_stack(struct WASMExecEnv *exec_env) #else lp_size = align_uint(all_cell_num * 5, 4); #endif - if (lp_size > 0) { + if (lp_size > 0 && !is_tiny_frame(exec_env)) { if (!(frame.lp = wasm_runtime_malloc(lp_size))) { destroy_c_api_frames(module_inst->frames); return false; } - bh_memcpy_s(frame.lp, lp_size, cur_frame->lp, lp_size); + bh_memcpy_s(frame.lp, lp_size, lp, lp_size); #if WASM_ENABLE_GC != 0 uint32 local_ref_flags_cell_num = @@ -3894,9 +4122,8 @@ aot_create_call_stack(struct WASMExecEnv *exec_env) .local_ref_flag_cell_num; uint8 *local_ref_flags = module->func_local_ref_flags[frame.func_index].local_ref_flags; - frame.sp = frame.lp + (cur_frame->sp - cur_frame->lp); - frame.frame_ref = (uint8 *)frame.lp - + (cur_frame->frame_ref - (uint8 *)cur_frame->lp); + frame.sp = frame.lp + (sp - lp); + frame.frame_ref = (uint8 *)frame.lp + (frame_ref - (uint8 *)lp); /* copy local ref flags from AOT module */ bh_memcpy_s(frame.frame_ref, local_ref_flags_cell_num, local_ref_flags, lp_size); @@ -3910,7 +4137,7 @@ aot_create_call_stack(struct WASMExecEnv *exec_env) return false; } - cur_frame = cur_frame->prev_frame; + top_frame = get_prev_frame(exec_env, top_frame); } return true; @@ -4889,6 +5116,18 @@ aot_const_str_set_insert(const uint8 *str, int32 len, AOTModule *module, return c_str; } +#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0 +AOTModule *g_dynamic_aot_module = NULL; + +void __attribute__((noinline)) __enable_dynamic_aot_debug(void) +{ + /* empty implementation. */ +} + +void (*__enable_dynamic_aot_debug_ptr)(void) + __attribute__((visibility("default"))) = __enable_dynamic_aot_debug; +#endif + bool aot_set_module_name(AOTModule *module, const char *name, char *error_buf, uint32_t error_buf_size) @@ -4902,6 +5141,12 @@ aot_set_module_name(AOTModule *module, const char *name, char *error_buf, false, #endif error_buf, error_buf_size); +#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0 + /* export g_dynamic_aot_module for dynamic aot debug */ + g_dynamic_aot_module = module; + /* trigger breakpoint __enable_dynamic_aot_debug */ + (*__enable_dynamic_aot_debug_ptr)(); +#endif return module->name != NULL; } @@ -4910,3 +5155,125 @@ aot_get_module_name(AOTModule *module) { return module->name; } + +bool +aot_resolve_symbols(AOTModule *module) +{ + bool ret = true; + uint32 idx; + for (idx = 0; idx < module->import_func_count; ++idx) { + AOTImportFunc *aot_import_func = &module->import_funcs[idx]; + if (!aot_import_func->func_ptr_linked) { + if (!aot_resolve_import_func(module, aot_import_func)) { + LOG_WARNING("Failed to link function (%s, %s)", + aot_import_func->module_name, + aot_import_func->func_name); + ret = false; + } + } + } + return ret; +} + +#if WASM_ENABLE_MULTI_MODULE != 0 +static void * +aot_resolve_function(const AOTModule *module, const char *function_name, + const AOTFuncType *expected_function_type, char *error_buf, + uint32 error_buf_size); + +static void * +aot_resolve_function_ex(const char *module_name, const char *function_name, + const AOTFuncType *expected_function_type, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg || module_reg->module_type != Wasm_Module_AoT) { + LOG_DEBUG("can not find a module named %s for function %s", module_name, + function_name); + set_error_buf(error_buf, error_buf_size, "unknown import"); + return NULL; + } + return aot_resolve_function((AOTModule *)module_reg, function_name, + expected_function_type, error_buf, + error_buf_size); +} + +static void * +aot_resolve_function(const AOTModule *module, const char *function_name, + const AOTFuncType *expected_function_type, char *error_buf, + uint32 error_buf_size) +{ + void *function = NULL; + AOTExport *export = NULL; + AOTFuncType *target_function_type = NULL; + + export = loader_find_export((WASMModuleCommon *)module, module->name, + function_name, EXPORT_KIND_FUNC, error_buf, + error_buf_size); + if (!export) { + return NULL; + } + + /* resolve function type and function */ + if (export->index < module->import_func_count) { + target_function_type = module->import_funcs[export->index].func_type; + function = module->import_funcs[export->index].func_ptr_linked; + } + else { + target_function_type = + (AOTFuncType *)module + ->types[module->func_type_indexes[export->index + - module->import_func_count]]; + function = + (module->func_ptrs[export->index - module->import_func_count]); + } + /* check function type */ + if (!wasm_type_equal((WASMType *)expected_function_type, + (WASMType *)target_function_type, module->types, + module->type_count)) { + LOG_DEBUG("%s.%s failed the type check", module->name, function_name); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + return function; +} +#endif /* end of WASM_ENABLE_MULTI_MODULE */ + +bool +aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func) +{ +#if WASM_ENABLE_MULTI_MODULE != 0 + char error_buf[128]; + AOTModule *sub_module = NULL; +#endif + import_func->func_ptr_linked = wasm_native_resolve_symbol( + import_func->module_name, import_func->func_name, + import_func->func_type, &import_func->signature, + &import_func->attachment, &import_func->call_conv_raw); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (!import_func->func_ptr_linked) { + if (!wasm_runtime_is_built_in_module(import_func->module_name)) { + sub_module = (AOTModule *)wasm_runtime_load_depended_module( + (WASMModuleCommon *)module, import_func->module_name, error_buf, + sizeof(error_buf)); + if (!sub_module) { + LOG_WARNING("Failed to load sub module: %s", error_buf); + } + if (!sub_module) + import_func->func_ptr_linked = aot_resolve_function_ex( + import_func->module_name, import_func->func_name, + import_func->func_type, error_buf, sizeof(error_buf)); + else + import_func->func_ptr_linked = aot_resolve_function( + sub_module, import_func->func_name, import_func->func_type, + error_buf, sizeof(error_buf)); + if (!import_func->func_ptr_linked) { + LOG_WARNING("Failed to link function: %s", error_buf); + } + } + } +#endif + return import_func->func_ptr_linked != NULL; +} diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 0eb647987..bf5e4366c 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -25,12 +25,16 @@ extern "C" { #define WASM_FEATURE_REF_TYPES (1 << 3) #define WASM_FEATURE_GARBAGE_COLLECTION (1 << 4) #define WASM_FEATURE_EXCEPTION_HANDLING (1 << 5) -#define WASM_FEATURE_MEMORY64 (1 << 6) +#define WASM_FEATURE_TINY_STACK_FRAME (1 << 6) #define WASM_FEATURE_MULTI_MEMORY (1 << 7) #define WASM_FEATURE_DYNAMIC_LINKING (1 << 8) #define WASM_FEATURE_COMPONENT_MODEL (1 << 9) #define WASM_FEATURE_RELAXED_SIMD (1 << 10) #define WASM_FEATURE_FLEXIBLE_VECTORS (1 << 11) +/* Stack frame is created at the beginning of the function, + * and not at the beginning of each function call */ +#define WASM_FEATURE_FRAME_PER_FUNCTION (1 << 12) +#define WASM_FEATURE_FRAME_NO_FUNC_IDX (1 << 13) typedef enum AOTSectionType { AOT_SECTION_TYPE_TARGET_INFO = 0, @@ -39,6 +43,10 @@ typedef enum AOTSectionType { AOT_SECTION_TYPE_FUNCTION = 3, AOT_SECTION_TYPE_EXPORT = 4, AOT_SECTION_TYPE_RELOCATION = 5, + /* + * Note: We haven't had anything to use AOT_SECTION_TYPE_SIGNATURE. + * It's just reserved for possible module signing features. + */ AOT_SECTION_TYPE_SIGNATURE = 6, AOT_SECTION_TYPE_CUSTOM = 100, } AOTSectionType; @@ -103,6 +111,14 @@ typedef struct AOTFunctionInstance { typedef struct AOTModuleInstanceExtra { DefPointer(const uint32 *, stack_sizes); + /* + * Adjusted shared heap based addr to simple the calculation + * in the aot code. The value is: + * shared_heap->base_addr - shared_heap->start_off + */ + DefPointer(uint8 *, shared_heap_base_addr_adj); + MemBound shared_heap_start_off; + WASMModuleInstanceExtraCommon common; AOTFunctionInstance **functions; uint32 function_count; @@ -111,6 +127,10 @@ typedef struct AOTModuleInstanceExtra { bh_list *sub_module_inst_list; WASMModuleInstanceCommon **import_func_module_insts; #endif + +#if WASM_ENABLE_SHARED_HEAP != 0 + WASMSharedHeap *shared_heap; +#endif } AOTModuleInstanceExtra; #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) @@ -322,6 +342,10 @@ typedef struct AOTModule { /* `.data` and `.text` sections merged into one large mmaped section */ uint8 *merged_data_text_sections; uint32 merged_data_text_sections_size; + +#if WASM_ENABLE_AOT_STACK_FRAME != 0 + uint32 feature_flags; +#endif } AOTModule; #define AOTMemoryInstance WASMMemoryInstance @@ -480,6 +504,18 @@ aot_load_from_sections(AOTSection *section_list, char *error_buf, void aot_unload(AOTModule *module); +/** + * Resolve symbols for an AOT module + */ +bool +aot_resolve_symbols(AOTModule *module); + +/** + * Helper function to resolve a single function + */ +bool +aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func); + /** * Instantiate a AOT module. * @@ -520,6 +556,15 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst); AOTFunctionInstance * aot_lookup_function(const AOTModuleInstance *module_inst, const char *name); +AOTMemoryInstance * +aot_lookup_memory(AOTModuleInstance *module_inst, char const *name); + +AOTMemoryInstance * +aot_get_default_memory(AOTModuleInstance *module_inst); + +AOTMemoryInstance * +aot_get_memory_with_index(AOTModuleInstance *module_inst, uint32 index); + /** * Get a function in the AOT module instance. * @@ -637,7 +682,7 @@ aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str, void **p_native_addr); uint32 -aot_get_plt_table_size(); +aot_get_plt_table_size(void); void * aot_memmove(void *dest, const void *src, size_t n); diff --git a/core/iwasm/aot/arch/aot_reloc_aarch64.c b/core/iwasm/aot/arch/aot_reloc_aarch64.c index b4bb6024a..26815334f 100644 --- a/core/iwasm/aot/arch/aot_reloc_aarch64.c +++ b/core/iwasm/aot/arch/aot_reloc_aarch64.c @@ -53,12 +53,6 @@ get_target_symbol_map(uint32 *sym_num) return target_sym_map; } -#if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__) -#define BUILD_TARGET_AARCH64_DEFAULT "arm64" -#else -#define BUILD_TARGET_AARCH64_DEFAULT "aarch64v8" -#endif - void get_current_target(char *target_buf, uint32 target_buf_size) { @@ -68,8 +62,8 @@ get_current_target(char *target_buf, uint32 target_buf_size) /* Set to "aarch64v8" by default if sub version isn't specified */ if (strcmp(s, "AARCH64") == 0) { - s = BUILD_TARGET_AARCH64_DEFAULT; - s_size = sizeof(BUILD_TARGET_AARCH64_DEFAULT); + s = "aarch64v8"; + s_size = 9; /* strlen("aarch64v8"); */ } if (target_buf_size < s_size) { s_size = target_buf_size; @@ -83,10 +77,9 @@ get_current_target(char *target_buf, uint32 target_buf_size) /* Ensure the string is null byte ('\0') terminated */ *d = '\0'; } -#undef BUILD_TARGET_AARCH64_DEFAULT static uint32 -get_plt_item_size() +get_plt_item_size(void) { /* 6*4 bytes instructions and 8 bytes symbol address */ return 32; diff --git a/core/iwasm/aot/arch/aot_reloc_arm.c b/core/iwasm/aot/arch/aot_reloc_arm.c index bb492bfeb..0be17ef4c 100644 --- a/core/iwasm/aot/arch/aot_reloc_arm.c +++ b/core/iwasm/aot/arch/aot_reloc_arm.c @@ -12,102 +12,102 @@ #define R_ARM_MOVT_ABS 44 /* clang-format off */ -void __adddf3(); -void __addsf3(); -void __aeabi_d2f(); -void __aeabi_d2iz(); -void __aeabi_d2lz(); -void __aeabi_d2uiz(); -void __aeabi_d2ulz(); -void __aeabi_dadd(); -void __aeabi_dcmpeq(); -void __aeabi_dcmpge(); -void __aeabi_dcmpgt(); -void __aeabi_dcmple(); -void __aeabi_dcmplt(); -void __aeabi_dcmpun(); -void __aeabi_ddiv(); -void __aeabi_dmul(); -void __aeabi_dsub(); -void __aeabi_f2d(); -void __aeabi_f2iz(); -void __aeabi_f2lz(); -void __aeabi_f2ulz(); -void __aeabi_fadd(); -void __aeabi_fcmpeq(); -void __aeabi_fcmpge(); -void __aeabi_fcmpgt(); -void __aeabi_fcmple(); -void __aeabi_fcmplt(); -void __aeabi_fcmpun(); -void __aeabi_fdiv(); -void __aeabi_fmul(); -void __aeabi_fsub(); -void __aeabi_i2d(); -void __aeabi_i2f(); -void __aeabi_idiv(); -void __aeabi_idivmod(); -void __aeabi_l2d(); -void __aeabi_l2f(); -void __aeabi_ldivmod(); -void __aeabi_memclr(); -void __aeabi_memcpy(); -void __aeabi_memmove(); -void __aeabi_memset(); -void __aeabi_ui2d(); -void __aeabi_ui2f(); -void __aeabi_uidiv(); -void __aeabi_uidivmod(); -void __aeabi_ul2d(); -void __aeabi_ul2f(); -void __aeabi_uldivmod(); -void __clzsi2(); -void __divdf3(); -void __divdi3(); -void __divsf3(); -void __divsi3(); -void __eqdf2(); -void __eqsf2(); -void __extendsfdf2(); -void __fixdfdi(); -void __fixdfsi(); -void __fixsfdi(); -void __fixsfsi(); -void __fixunsdfdi(); -void __fixunsdfsi(); -void __fixunssfdi(); -void __floatdidf(); -void __floatdisf(); -void __floatsidf(); -void __floatsisf(); -void __floatundidf(); -void __floatundisf(); -void __floatunsidf(); -void __floatunsisf(); -void __gedf2(); -void __gesf2(); -void __gtdf2(); -void __gtsf2(); -void __ledf2(); -void __lesf2(); -void __ltdf2(); -void __ltsf2(); -void __moddi3(); -void __modsi3(); -void __muldf3(); -void __mulsf3(); -void __nedf2(); -void __nesf2(); -void __subdf3(); -void __subsf3(); -void __truncdfsf2(); -void __udivdi3(); -void __udivmoddi4(); -void __udivsi3(); -void __umoddi3(); -void __umodsi3(); -void __unorddf2(); -void __unordsf2(); +void __adddf3(void); +void __addsf3(void); +void __aeabi_d2f(void); +void __aeabi_d2iz(void); +void __aeabi_d2lz(void); +void __aeabi_d2uiz(void); +void __aeabi_d2ulz(void); +void __aeabi_dadd(void); +void __aeabi_dcmpeq(void); +void __aeabi_dcmpge(void); +void __aeabi_dcmpgt(void); +void __aeabi_dcmple(void); +void __aeabi_dcmplt(void); +void __aeabi_dcmpun(void); +void __aeabi_ddiv(void); +void __aeabi_dmul(void); +void __aeabi_dsub(void); +void __aeabi_f2d(void); +void __aeabi_f2iz(void); +void __aeabi_f2lz(void); +void __aeabi_f2ulz(void); +void __aeabi_fadd(void); +void __aeabi_fcmpeq(void); +void __aeabi_fcmpge(void); +void __aeabi_fcmpgt(void); +void __aeabi_fcmple(void); +void __aeabi_fcmplt(void); +void __aeabi_fcmpun(void); +void __aeabi_fdiv(void); +void __aeabi_fmul(void); +void __aeabi_fsub(void); +void __aeabi_i2d(void); +void __aeabi_i2f(void); +void __aeabi_idiv(void); +void __aeabi_idivmod(void); +void __aeabi_l2d(void); +void __aeabi_l2f(void); +void __aeabi_ldivmod(void); +void __aeabi_memclr(void); +void __aeabi_memcpy(void); +void __aeabi_memmove(void); +void __aeabi_memset(void); +void __aeabi_ui2d(void); +void __aeabi_ui2f(void); +void __aeabi_uidiv(void); +void __aeabi_uidivmod(void); +void __aeabi_ul2d(void); +void __aeabi_ul2f(void); +void __aeabi_uldivmod(void); +void __clzsi2(void); +void __divdf3(void); +void __divdi3(void); +void __divsf3(void); +void __divsi3(void); +void __eqdf2(void); +void __eqsf2(void); +void __extendsfdf2(void); +void __fixdfdi(void); +void __fixdfsi(void); +void __fixsfdi(void); +void __fixsfsi(void); +void __fixunsdfdi(void); +void __fixunsdfsi(void); +void __fixunssfdi(void); +void __floatdidf(void); +void __floatdisf(void); +void __floatsidf(void); +void __floatsisf(void); +void __floatundidf(void); +void __floatundisf(void); +void __floatunsidf(void); +void __floatunsisf(void); +void __gedf2(void); +void __gesf2(void); +void __gtdf2(void); +void __gtsf2(void); +void __ledf2(void); +void __lesf2(void); +void __ltdf2(void); +void __ltsf2(void); +void __moddi3(void); +void __modsi3(void); +void __muldf3(void); +void __mulsf3(void); +void __nedf2(void); +void __nesf2(void); +void __subdf3(void); +void __subsf3(void); +void __truncdfsf2(void); +void __udivdi3(void); +void __udivmoddi4(void); +void __udivsi3(void); +void __umoddi3(void); +void __umodsi3(void); +void __unorddf2(void); +void __unordsf2(void); /* clang-format on */ static SymbolMap target_sym_map[] = { @@ -255,7 +255,7 @@ get_current_target(char *target_buf, uint32 target_buf_size) #undef BUILD_TARGET_ARM_DEFAULT uint32 -get_plt_item_size() +get_plt_item_size(void) { /* 8 bytes instructions and 4 bytes symbol address */ return 12; diff --git a/core/iwasm/aot/arch/aot_reloc_mips.c b/core/iwasm/aot/arch/aot_reloc_mips.c index f9f06a053..4b856119c 100644 --- a/core/iwasm/aot/arch/aot_reloc_mips.c +++ b/core/iwasm/aot/arch/aot_reloc_mips.c @@ -28,7 +28,7 @@ get_current_target(char *target_buf, uint32 target_buf_size) } static uint32 -get_plt_item_size() +get_plt_item_size(void) { return 0; } diff --git a/core/iwasm/aot/arch/aot_reloc_riscv.c b/core/iwasm/aot/arch/aot_reloc_riscv.c index b87bb2000..8df9f9f8e 100644 --- a/core/iwasm/aot/arch/aot_reloc_riscv.c +++ b/core/iwasm/aot/arch/aot_reloc_riscv.c @@ -24,6 +24,7 @@ #undef NEED_SOFT_I32_DIV #undef NEED_SOFT_I64_MUL #undef NEED_SOFT_I64_DIV +#undef NEED_SOFT_ATOMIC #ifdef __riscv_flen #if __riscv_flen == 32 @@ -48,59 +49,66 @@ #define NEED_SOFT_I64_DIV #endif +#ifndef __riscv_atomic +#define NEED_SOFT_ATOMIC +#endif + /* clang-format off */ -void __adddf3(); -void __addsf3(); -void __divdf3(); -void __divdi3(); -void __divsf3(); -void __divsi3(); -void __eqdf2(); -void __eqsf2(); -void __extendsfdf2(); -void __fixdfdi(); -void __fixdfsi(); -void __fixsfdi(); -void __fixsfsi(); -void __fixunsdfdi(); -void __fixunsdfsi(); -void __fixunssfdi(); -void __fixunssfsi(); -void __floatdidf(); -void __floatdisf(); -void __floatsidf(); -void __floatsisf(); -void __floatundidf(); -void __floatundisf(); -void __floatunsidf(); -void __floatunsisf(); -void __gedf2(); -void __gesf2(); -void __gtdf2(); -void __gtsf2(); -void __ledf2(); -void __lesf2(); -void __ltdf2(); -void __ltsf2(); -void __moddi3(); -void __modsi3(); -void __muldf3(); -void __muldi3(); -void __mulsf3(); -void __mulsi3(); -void __nedf2(); -void __negdf2(); -void __negsf2(); -void __nesf2(); -void __subdf3(); -void __subsf3(); -void __truncdfsf2(); -void __udivdi3(); -void __udivsi3(); -void __umoddi3(); -void __umodsi3(); -void __unorddf2(); -void __unordsf2(); +void __adddf3(void); +void __addsf3(void); +void __divdf3(void); +void __divdi3(void); +void __divsf3(void); +void __divsi3(void); +void __eqdf2(void); +void __eqsf2(void); +void __extendsfdf2(void); +void __fixdfdi(void); +void __fixdfsi(void); +void __fixsfdi(void); +void __fixsfsi(void); +void __fixunsdfdi(void); +void __fixunsdfsi(void); +void __fixunssfdi(void); +void __fixunssfsi(void); +void __floatdidf(void); +void __floatdisf(void); +void __floatsidf(void); +void __floatsisf(void); +void __floatundidf(void); +void __floatundisf(void); +void __floatunsidf(void); +void __floatunsisf(void); +void __gedf2(void); +void __gesf2(void); +void __gtdf2(void); +void __gtsf2(void); +void __ledf2(void); +void __lesf2(void); +void __ltdf2(void); +void __ltsf2(void); +void __moddi3(void); +void __modsi3(void); +void __muldf3(void); +void __muldi3(void); +void __mulsf3(void); +void __mulsi3(void); +void __nedf2(void); +void __negdf2(void); +void __negsf2(void); +void __nesf2(void); +void __subdf3(void); +void __subsf3(void); +void __truncdfsf2(void); +void __udivdi3(void); +void __udivsi3(void); +void __umoddi3(void); +void __umodsi3(void); +void __unorddf2(void); +void __unordsf2(void); +bool __atomic_compare_exchange_4(volatile void *, void *, unsigned int, + bool, int, int); +void __atomic_store_4(volatile void *, unsigned int, int); /* clang-format on */ static SymbolMap target_sym_map[] = { @@ -127,6 +135,7 @@ static SymbolMap target_sym_map[] = { * to convert float and long long */ REG_SYM(__floatundisf), + REG_SYM(__floatdisf), #endif #ifdef NEED_SOFT_DP REG_SYM(__adddf3), @@ -175,6 +184,10 @@ static SymbolMap target_sym_map[] = { REG_SYM(__moddi3), REG_SYM(__udivdi3), REG_SYM(__umoddi3), +#endif +#ifdef NEED_SOFT_ATOMIC + REG_SYM(__atomic_compare_exchange_4), + REG_SYM(__atomic_store_4), #endif /* clang-format on */ }; @@ -193,7 +206,7 @@ get_current_target(char *target_buf, uint32 target_buf_size) } uint32 -get_plt_item_size() +get_plt_item_size(void) { #if __riscv_xlen == 64 /* auipc + ld + jalr + nop + addr */ diff --git a/core/iwasm/aot/arch/aot_reloc_thumb.c b/core/iwasm/aot/arch/aot_reloc_thumb.c index f90507dec..c0957a42a 100644 --- a/core/iwasm/aot/arch/aot_reloc_thumb.c +++ b/core/iwasm/aot/arch/aot_reloc_thumb.c @@ -14,102 +14,102 @@ #define R_ARM_THM_MOVT_PREL 50 /* clang-format off */ -void __adddf3(); -void __addsf3(); -void __aeabi_d2f(); -void __aeabi_d2iz(); -void __aeabi_d2lz(); -void __aeabi_d2uiz(); -void __aeabi_d2ulz(); -void __aeabi_dadd(); -void __aeabi_dcmpeq(); -void __aeabi_dcmpge(); -void __aeabi_dcmpgt(); -void __aeabi_dcmple(); -void __aeabi_dcmplt(); -void __aeabi_dcmpun(); -void __aeabi_ddiv(); -void __aeabi_dmul(); -void __aeabi_dsub(); -void __aeabi_f2d(); -void __aeabi_f2iz(); -void __aeabi_f2lz(); -void __aeabi_f2ulz(); -void __aeabi_fadd(); -void __aeabi_fcmpeq(); -void __aeabi_fcmpge(); -void __aeabi_fcmpgt(); -void __aeabi_fcmple(); -void __aeabi_fcmplt(); -void __aeabi_fcmpun(); -void __aeabi_fdiv(); -void __aeabi_fmul(); -void __aeabi_fsub(); -void __aeabi_i2d(); -void __aeabi_i2f(); -void __aeabi_idiv(); -void __aeabi_idivmod(); -void __aeabi_l2d(); -void __aeabi_l2f(); -void __aeabi_ldivmod(); -void __aeabi_llsl(); -void __aeabi_llsr(); -void __aeabi_lmul(); -void __aeabi_ui2d(); -void __aeabi_ui2f(); -void __aeabi_uidiv(); -void __aeabi_uidivmod(); -void __aeabi_ul2d(); -void __aeabi_ul2f(); -void __aeabi_uldivmod(); -void __ashldi3(); -void __clzsi2(); -void __divdf3(); -void __divdi3(); -void __divsi3(); -void __eqdf2(); -void __eqsf2(); -void __extendsfdf2(); -void __fixdfdi(); -void __fixdfsi(); -void __fixsfdi(); -void __fixunsdfdi(); -void __fixunsdfsi(); -void __fixunssfdi(); -void __floatdidf(); -void __floatdisf(); -void __floatsidf(); -void __floatsisf(); -void __floatundidf(); -void __floatundisf(); -void __floatunsidf(); -void __floatunsisf(); -void __gedf2(); -void __gesf2(); -void __gtdf2(); -void __gtsf2(); -void __ledf2(); -void __lesf2(); -void __lshrdi3(); -void __ltdf2(); -void __ltsf2(); -void __moddi3(); -void __modsi3(); -void __muldf3(); -void __muldi3(); -void __mulsf3(); -void __nedf2(); -void __nesf2(); -void __subdf3(); -void __subsf3(); -void __truncdfsf2(); -void __udivdi3(); -void __udivmoddi4(); -void __udivsi3(); -void __umoddi3(); -void __umodsi3(); -void __unorddf2(); -void __unordsf2(); +void __adddf3(void); +void __addsf3(void); +void __aeabi_d2f(void); +void __aeabi_d2iz(void); +void __aeabi_d2lz(void); +void __aeabi_d2uiz(void); +void __aeabi_d2ulz(void); +void __aeabi_dadd(void); +void __aeabi_dcmpeq(void); +void __aeabi_dcmpge(void); +void __aeabi_dcmpgt(void); +void __aeabi_dcmple(void); +void __aeabi_dcmplt(void); +void __aeabi_dcmpun(void); +void __aeabi_ddiv(void); +void __aeabi_dmul(void); +void __aeabi_dsub(void); +void __aeabi_f2d(void); +void __aeabi_f2iz(void); +void __aeabi_f2lz(void); +void __aeabi_f2ulz(void); +void __aeabi_fadd(void); +void __aeabi_fcmpeq(void); +void __aeabi_fcmpge(void); +void __aeabi_fcmpgt(void); +void __aeabi_fcmple(void); +void __aeabi_fcmplt(void); +void __aeabi_fcmpun(void); +void __aeabi_fdiv(void); +void __aeabi_fmul(void); +void __aeabi_fsub(void); +void __aeabi_i2d(void); +void __aeabi_i2f(void); +void __aeabi_idiv(void); +void __aeabi_idivmod(void); +void __aeabi_l2d(void); +void __aeabi_l2f(void); +void __aeabi_ldivmod(void); +void __aeabi_llsl(void); +void __aeabi_llsr(void); +void __aeabi_lmul(void); +void __aeabi_ui2d(void); +void __aeabi_ui2f(void); +void __aeabi_uidiv(void); +void __aeabi_uidivmod(void); +void __aeabi_ul2d(void); +void __aeabi_ul2f(void); +void __aeabi_uldivmod(void); +void __ashldi3(void); +void __clzsi2(void); +void __divdf3(void); +void __divdi3(void); +void __divsi3(void); +void __eqdf2(void); +void __eqsf2(void); +void __extendsfdf2(void); +void __fixdfdi(void); +void __fixdfsi(void); +void __fixsfdi(void); +void __fixunsdfdi(void); +void __fixunsdfsi(void); +void __fixunssfdi(void); +void __floatdidf(void); +void __floatdisf(void); +void __floatsidf(void); +void __floatsisf(void); +void __floatundidf(void); +void __floatundisf(void); +void __floatunsidf(void); +void __floatunsisf(void); +void __gedf2(void); +void __gesf2(void); +void __gtdf2(void); +void __gtsf2(void); +void __ledf2(void); +void __lesf2(void); +void __lshrdi3(void); +void __ltdf2(void); +void __ltsf2(void); +void __moddi3(void); +void __modsi3(void); +void __muldf3(void); +void __muldi3(void); +void __mulsf3(void); +void __nedf2(void); +void __nesf2(void); +void __subdf3(void); +void __subsf3(void); +void __truncdfsf2(void); +void __udivdi3(void); +void __udivmoddi4(void); +void __udivsi3(void); +void __umoddi3(void); +void __umodsi3(void); +void __unorddf2(void); +void __unordsf2(void); /* clang-format on */ static SymbolMap target_sym_map[] = { @@ -259,7 +259,7 @@ get_current_target(char *target_buf, uint32 target_buf_size) #undef BUILD_TARGET_THUMB_V4T uint32 -get_plt_item_size() +get_plt_item_size(void) { /* 16 bytes instructions and 4 bytes symbol address */ return 20; diff --git a/core/iwasm/aot/arch/aot_reloc_x86_64.c b/core/iwasm/aot/arch/aot_reloc_x86_64.c index d1f5cb5ac..fe18d79c6 100644 --- a/core/iwasm/aot/arch/aot_reloc_x86_64.c +++ b/core/iwasm/aot/arch/aot_reloc_x86_64.c @@ -58,7 +58,7 @@ get_current_target(char *target_buf, uint32 target_buf_size) } static uint32 -get_plt_item_size() +get_plt_item_size(void) { /* size of mov instruction and jmp instruction */ return 12; diff --git a/core/iwasm/aot/arch/aot_reloc_xtensa.c b/core/iwasm/aot/arch/aot_reloc_xtensa.c index a29c9f2b9..fca1b80da 100644 --- a/core/iwasm/aot/arch/aot_reloc_xtensa.c +++ b/core/iwasm/aot/arch/aot_reloc_xtensa.c @@ -10,44 +10,44 @@ /* clang-format off */ /* for soft-float */ -void __floatsidf(); -void __divdf3(); -void __ltdf2(); +void __floatsidf(void); +void __divdf3(void); +void __ltdf2(void); /* for mul32 */ -void __mulsi3(); -void __muldi3(); +void __mulsi3(void); +void __muldi3(void); -void __modsi3(); +void __modsi3(void); -void __divdi3(); +void __divdi3(void); -void __udivdi3(); -void __unorddf2(); -void __adddf3(); -void __eqdf2(); -void __muldf3(); -void __gedf2(); -void __ledf2(); -void __fixunsdfsi(); -void __floatunsidf(); -void __subdf3(); -void __nedf2(); -void __fixdfsi(); -void __moddi3(); -void __extendsfdf2(); -void __truncdfsf2(); -void __gtdf2(); -void __umoddi3(); -void __floatdidf(); -void __divsf3(); -void __fixdfdi(); -void __floatundidf(); -void __fixsfdi(); -void __fixunssfdi(); -void __fixunsdfdi(); -void __floatdisf(); -void __floatundisf(); +void __udivdi3(void); +void __unorddf2(void); +void __adddf3(void); +void __eqdf2(void); +void __muldf3(void); +void __gedf2(void); +void __ledf2(void); +void __fixunsdfsi(void); +void __floatunsidf(void); +void __subdf3(void); +void __nedf2(void); +void __fixdfsi(void); +void __moddi3(void); +void __extendsfdf2(void); +void __truncdfsf2(void); +void __gtdf2(void); +void __umoddi3(void); +void __floatdidf(void); +void __divsf3(void); +void __fixdfdi(void); +void __floatundidf(void); +void __fixsfdi(void); +void __fixunssfdi(void); +void __fixunsdfdi(void); +void __floatdisf(void); +void __floatundisf(void); static SymbolMap target_sym_map[] = { @@ -119,7 +119,7 @@ get_current_target(char *target_buf, uint32 target_buf_size) } static uint32 -get_plt_item_size() +get_plt_item_size(void) { return 0; } diff --git a/core/iwasm/aot/debug/jit_debug.c b/core/iwasm/aot/debug/jit_debug.c index 261c20546..9f92dd393 100644 --- a/core/iwasm/aot/debug/jit_debug.c +++ b/core/iwasm/aot/debug/jit_debug.c @@ -69,10 +69,10 @@ typedef struct JITDescriptor { * and inline assembler statement inside. */ void attribute_noinline -__jit_debug_register_code(); +__jit_debug_register_code(void); void attribute_noinline -__jit_debug_register_code() +__jit_debug_register_code(void) { int x; *(char *)&x = '\0'; @@ -96,7 +96,7 @@ extern JITDescriptor __jit_debug_descriptor; * This gives the debugger an easy way to inject custom code to * handle the events. */ -void (*__jit_debug_register_code_ptr)() = __jit_debug_register_code; +void (*__jit_debug_register_code_ptr)(void) = __jit_debug_register_code; #ifdef __cplusplus } @@ -171,7 +171,7 @@ DestroyJITCodeEntryInternal(JITCodeEntry *entry) } bool -jit_debug_engine_init() +jit_debug_engine_init(void) { if (jit_debug_engine) { return true; @@ -194,7 +194,7 @@ jit_debug_engine_init() } void -jit_debug_engine_destroy() +jit_debug_engine_destroy(void) { if (jit_debug_engine) { WASMJITEntryNode *node, *node_next; diff --git a/core/iwasm/aot/debug/jit_debug.h b/core/iwasm/aot/debug/jit_debug.h index 5e3e36519..813c8b782 100644 --- a/core/iwasm/aot/debug/jit_debug.h +++ b/core/iwasm/aot/debug/jit_debug.h @@ -11,10 +11,10 @@ extern "C" { #endif bool -jit_debug_engine_init(); +jit_debug_engine_init(void); void -jit_debug_engine_destroy(); +jit_debug_engine_destroy(void); bool jit_code_entry_create(const uint8 *symfile_addr, uint64 symfile_size); diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 01109658f..5c1e9efd3 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -3391,8 +3391,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, if (export->kind == EXPORT_KIND_FUNC) { if (export->index == func->func_idx_rt) { func_comm_rt = - (AOTFunctionInstance *)inst_aot->export_functions - + export_func_j; + aot_lookup_function(inst_aot, export->name); ((wasm_func_t *)func)->func_comm_rt = func_comm_rt; break; } diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 7128b4c63..48465fc94 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -282,8 +282,13 @@ wasm_exec_env_set_thread_info(WASMExecEnv *exec_env) os_mutex_lock(&exec_env->wait_lock); #endif exec_env->handle = os_self_thread(); - exec_env->native_stack_boundary = - stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL; + if (exec_env->user_native_stack_boundary) + /* WASM_STACK_GUARD_SIZE isn't added for flexibility to developer, + he must ensure that enough guard bytes are kept. */ + exec_env->native_stack_boundary = exec_env->user_native_stack_boundary; + else + exec_env->native_stack_boundary = + stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL; exec_env->native_stack_top_min = (void *)UINTPTR_MAX; #if WASM_ENABLE_THREAD_MGR != 0 os_mutex_unlock(&exec_env->wait_lock); diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 53d248755..ce0c1fa7f 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -136,6 +136,10 @@ typedef struct WASMExecEnv { void *user_data; + /* The boundary of native stack set by host embedder. It is used + if it is not NULL when calling wasm functions. */ + uint8 *user_native_stack_boundary; + /* The native thread handle of current thread */ korp_tid handle; diff --git a/core/iwasm/common/wasm_loader_common.c b/core/iwasm/common/wasm_loader_common.c index 6dd31be2c..97ea5efd1 100644 --- a/core/iwasm/common/wasm_loader_common.c +++ b/core/iwasm/common/wasm_loader_common.c @@ -19,6 +19,37 @@ wasm_loader_set_error_buf(char *error_buf, uint32 error_buf_size, } } +#if WASM_ENABLE_MEMORY64 != 0 +bool +check_memory64_flags_consistency(WASMModule *module, char *error_buf, + uint32 error_buf_size, bool is_aot) +{ + uint32 i; + bool wasm64_flag, all_wasm64 = true, none_wasm64 = true; + + for (i = 0; i < module->import_memory_count; ++i) { + wasm64_flag = + module->import_memories[i].u.memory.mem_type.flags & MEMORY64_FLAG; + all_wasm64 &= wasm64_flag; + none_wasm64 &= !wasm64_flag; + } + + for (i = 0; i < module->memory_count; ++i) { + wasm64_flag = module->memories[i].flags & MEMORY64_FLAG; + all_wasm64 &= wasm64_flag; + none_wasm64 &= !wasm64_flag; + } + + if (!(all_wasm64 || none_wasm64)) { + wasm_loader_set_error_buf( + error_buf, error_buf_size, + "inconsistent limits wasm64 flags for memory sections", is_aot); + return false; + } + return true; +} +#endif + bool wasm_memory_check_flags(const uint8 mem_flag, char *error_buf, uint32 error_buf_size, bool is_aot) @@ -60,6 +91,37 @@ wasm_memory_check_flags(const uint8 mem_flag, char *error_buf, return true; } +bool +wasm_table_check_flags(const uint8 table_flag, char *error_buf, + uint32 error_buf_size, bool is_aot) +{ + /* Check whether certain features indicated by mem_flag are enabled in + * runtime */ + if (table_flag > MAX_TABLE_SIZE_FLAG) { + if (table_flag & SHARED_TABLE_FLAG) { + wasm_loader_set_error_buf(error_buf, error_buf_size, + "tables cannot be shared", is_aot); + } +#if WASM_ENABLE_MEMORY64 == 0 + if (table_flag & TABLE64_FLAG) { + wasm_loader_set_error_buf(error_buf, error_buf_size, + "invalid limits flags(table64 flag was " + "found, please enable memory64)", + is_aot); + return false; + } +#endif + } + + if (table_flag > MAX_TABLE_SIZE_FLAG + TABLE64_FLAG) { + wasm_loader_set_error_buf(error_buf, error_buf_size, + "invalid limits flags", is_aot); + return false; + } + + return true; +} + /* * compare with a bigger type set in `wasm_value_type_size_internal()`, * this function will only cover global value type, function's param diff --git a/core/iwasm/common/wasm_loader_common.h b/core/iwasm/common/wasm_loader_common.h index d574110ba..81174fb26 100644 --- a/core/iwasm/common/wasm_loader_common.h +++ b/core/iwasm/common/wasm_loader_common.h @@ -13,10 +13,22 @@ extern "C" { #endif +#if WASM_ENABLE_MEMORY64 != 0 +/* check consistency of memory64 flags across all memories, + * they must be either all wasm64 or all wasm32 */ +bool +check_memory64_flags_consistency(WASMModule *module, char *error_buf, + uint32 error_buf_size, bool is_aot); +#endif + bool wasm_memory_check_flags(const uint8 mem_flag, char *error_buf, uint32 error_buf_size, bool is_aot); +bool +wasm_table_check_flags(const uint8 table_flag, char *error_buf, + uint32 error_buf_size, bool is_aot); + bool is_valid_value_type(uint8 value_tpye); diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 71d337549..5f5a1be90 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -13,6 +13,10 @@ #include "../common/wasm_shared_memory.h" #endif +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../libraries/thread-mgr/thread_manager.h" +#endif + typedef enum Memory_Mode { MEMORY_MODE_UNKNOWN = 0, MEMORY_MODE_POOL, @@ -24,6 +28,11 @@ static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN; static mem_allocator_t pool_allocator = NULL; +#if WASM_ENABLE_SHARED_HEAP != 0 +static WASMSharedHeap *shared_heap_list = NULL; +static korp_mutex shared_heap_list_lock; +#endif + static enlarge_memory_error_callback_t enlarge_memory_error_cb; static void *enlarge_memory_error_user_data; @@ -132,16 +141,371 @@ is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst) #endif } +#if WASM_ENABLE_SHARED_HEAP != 0 +static void * +wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size); +static void +wasm_munmap_linear_memory(void *mapped_mem, uint64 commit_size, + uint64 map_size); + +static void * +runtime_malloc(uint64 size) +{ + void *mem; + + if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { + LOG_WARNING("Allocate memory failed"); + return NULL; + } + + memset(mem, 0, (uint32)size); + return mem; +} + +WASMSharedHeap * +wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args) +{ + uint64 heap_struct_size = sizeof(WASMSharedHeap), map_size; + uint32 size = init_args->size; + WASMSharedHeap *heap; + + if (size == 0) { + goto fail1; + } + + if (!(heap = runtime_malloc(heap_struct_size))) { + goto fail1; + } + + if (!(heap->heap_handle = + runtime_malloc(mem_allocator_get_heap_struct_size()))) { + goto fail2; + } + + size = align_uint(size, os_getpagesize()); + heap->size = size; + heap->start_off_mem64 = UINT64_MAX - heap->size + 1; + heap->start_off_mem32 = UINT32_MAX - heap->size + 1; + + if (size > APP_HEAP_SIZE_MAX || size < APP_HEAP_SIZE_MIN) { + LOG_WARNING("Invalid size of shared heap"); + goto fail3; + } + +#ifndef OS_ENABLE_HW_BOUND_CHECK + map_size = size; +#else + /* Totally 8G is mapped, the opcode load/store address range is 0 to 8G: + * ea = i + memarg.offset + * both i and memarg.offset are u32 in range 0 to 4G + * so the range of ea is 0 to 8G + */ + map_size = 8 * (uint64)BH_GB; +#endif + + if (!(heap->base_addr = wasm_mmap_linear_memory(map_size, size))) { + goto fail3; + } + if (!mem_allocator_create_with_struct_and_pool( + heap->heap_handle, heap_struct_size, heap->base_addr, size)) { + LOG_WARNING("init share heap failed"); + goto fail4; + } + + os_mutex_lock(&shared_heap_list_lock); + if (shared_heap_list == NULL) { + shared_heap_list = heap; + } + else { + heap->next = shared_heap_list; + shared_heap_list = heap; + } + os_mutex_unlock(&shared_heap_list_lock); + return heap; + +fail4: + wasm_munmap_linear_memory(heap->base_addr, size, map_size); +fail3: + wasm_runtime_free(heap->heap_handle); +fail2: + wasm_runtime_free(heap); +fail1: + return NULL; +} + +bool +wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst, + WASMSharedHeap *shared_heap) +{ + WASMMemoryInstance *memory = + wasm_get_default_memory((WASMModuleInstance *)module_inst); + uint64 linear_mem_size; + + if (!memory) + return false; + + linear_mem_size = memory->memory_data_size; + + /* check if linear memory and shared heap are overlapped */ + if ((memory->is_memory64 && linear_mem_size > shared_heap->start_off_mem64) + || (!memory->is_memory64 + && linear_mem_size > shared_heap->start_off_mem32)) { + LOG_WARNING("Linear memory address is overlapped with shared heap"); + return false; + } + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstanceExtra *e = + (WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e; + if (e->shared_heap) { + LOG_WARNING("A shared heap is already attached"); + return false; + } + e->shared_heap = shared_heap; +#if WASM_ENABLE_JIT != 0 +#if UINTPTR_MAX == UINT64_MAX + if (memory->is_memory64) + e->shared_heap_start_off.u64 = shared_heap->start_off_mem64; + else + e->shared_heap_start_off.u64 = shared_heap->start_off_mem32; + e->shared_heap_base_addr_adj = + shared_heap->base_addr - e->shared_heap_start_off.u64; +#else + e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32; + e->shared_heap_base_addr_adj = + shared_heap->base_addr - e->shared_heap_start_off.u32[0]; +#endif +#endif /* end of WASM_ENABLE_JIT != 0 */ + } +#endif /* end of WASM_ENABLE_INTERP != 0 */ +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e; + if (e->shared_heap) { + LOG_WARNING("A shared heap is already attached"); + return false; + } + e->shared_heap = shared_heap; +#if UINTPTR_MAX == UINT64_MAX + if (memory->is_memory64) + e->shared_heap_start_off.u64 = shared_heap->start_off_mem64; + else + e->shared_heap_start_off.u64 = shared_heap->start_off_mem32; + e->shared_heap_base_addr_adj = + shared_heap->base_addr - e->shared_heap_start_off.u64; +#else + e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32; + e->shared_heap_base_addr_adj = + shared_heap->base_addr - e->shared_heap_start_off.u32[0]; +#endif + } +#endif /* end of WASM_ENABLE_AOT != 0 */ + + return true; +} + +bool +wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst, + WASMSharedHeap *shared_heap) +{ +#if WASM_ENABLE_THREAD_MGR != 0 + return wasm_cluster_attach_shared_heap(module_inst, shared_heap); +#else + return wasm_runtime_attach_shared_heap_internal(module_inst, shared_heap); +#endif +} + +void +wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstanceExtra *e = + (WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e; + e->shared_heap = NULL; +#if WASM_ENABLE_JIT != 0 +#if UINTPTR_MAX == UINT64_MAX + e->shared_heap_start_off.u64 = UINT64_MAX; +#else + e->shared_heap_start_off.u32[0] = UINT32_MAX; +#endif + e->shared_heap_base_addr_adj = NULL; +#endif + } +#endif /* end of WASM_ENABLE_INTERP != 0 */ +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e; + e->shared_heap = NULL; +#if UINTPTR_MAX == UINT64_MAX + e->shared_heap_start_off.u64 = UINT64_MAX; +#else + e->shared_heap_start_off.u32[0] = UINT32_MAX; +#endif + e->shared_heap_base_addr_adj = NULL; + } +#endif /* end of WASM_ENABLE_AOT != 0 */ +} + +void +wasm_runtime_detach_shared_heap(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_detach_shared_heap(module_inst); +#else + wasm_runtime_detach_shared_heap_internal(module_inst); +#endif +} + +static WASMSharedHeap * +get_shared_heap(WASMModuleInstanceCommon *module_inst_comm) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + return ((WASMModuleInstance *)module_inst_comm)->e->shared_heap; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_comm) + ->e; + return e->shared_heap; + } +#endif + return NULL; +} + +WASMSharedHeap * +wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm) +{ + return get_shared_heap(module_inst_comm); +} + +static bool +is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst, + bool is_memory64, uint64 app_offset, uint32 bytes) +{ + WASMSharedHeap *heap = get_shared_heap(module_inst); + + if (!heap) { + return false; + } + + if (bytes == 0) { + bytes = 1; + } + + if (!is_memory64) { + if (app_offset >= heap->start_off_mem32 + && app_offset <= UINT32_MAX - bytes + 1) { + return true; + } + } + else { + if (app_offset >= heap->start_off_mem64 + && app_offset <= UINT64_MAX - bytes + 1) { + return true; + } + } + + return false; +} + +static bool +is_native_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst, + uint8 *addr, uint32 bytes) +{ + WASMSharedHeap *heap = get_shared_heap(module_inst); + + if (heap && addr >= heap->base_addr + && addr + bytes <= heap->base_addr + heap->size + && addr + bytes > addr) { + return true; + } + return false; +} + +uint64 +wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst, + uint64_t size, void **p_native_addr) +{ + WASMMemoryInstance *memory = + wasm_get_default_memory((WASMModuleInstance *)module_inst); + WASMSharedHeap *shared_heap = get_shared_heap(module_inst); + void *native_addr = NULL; + + if (!memory || !shared_heap) + return 0; + + native_addr = mem_allocator_malloc(shared_heap->heap_handle, size); + if (!native_addr) + return 0; + + if (p_native_addr) { + *p_native_addr = native_addr; + } + + if (memory->is_memory64) + return shared_heap->start_off_mem64 + + ((uint8 *)native_addr - shared_heap->base_addr); + else + return shared_heap->start_off_mem32 + + ((uint8 *)native_addr - shared_heap->base_addr); +} + +void +wasm_runtime_shared_heap_free(WASMModuleInstanceCommon *module_inst, uint64 ptr) +{ + WASMMemoryInstance *memory = + wasm_get_default_memory((WASMModuleInstance *)module_inst); + WASMSharedHeap *shared_heap = get_shared_heap(module_inst); + uint8 *addr = NULL; + + if (!memory || !shared_heap) { + return; + } + + if (memory->is_memory64) { + if (ptr < shared_heap->start_off_mem64) { /* ptr can not > UINT64_MAX */ + LOG_WARNING("The address to free isn't in shared heap"); + return; + } + addr = shared_heap->base_addr + (ptr - shared_heap->start_off_mem64); + } + else { + if (ptr < shared_heap->start_off_mem32 || ptr > UINT32_MAX) { + LOG_WARNING("The address to free isn't in shared heap"); + return; + } + addr = shared_heap->base_addr + (ptr - shared_heap->start_off_mem32); + } + + mem_allocator_free(shared_heap->heap_handle, addr); +} +#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */ + bool wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, const MemAllocOption *alloc_option) { + bool ret = false; + +#if WASM_ENABLE_SHARED_HEAP != 0 + if (os_mutex_init(&shared_heap_list_lock)) { + return false; + } +#endif + if (mem_alloc_type == Alloc_With_Pool) { - return wasm_memory_init_with_pool(alloc_option->pool.heap_buf, - alloc_option->pool.heap_size); + ret = wasm_memory_init_with_pool(alloc_option->pool.heap_buf, + alloc_option->pool.heap_size); } else if (mem_alloc_type == Alloc_With_Allocator) { - return wasm_memory_init_with_allocator( + ret = wasm_memory_init_with_allocator( #if WASM_MEM_ALLOC_WITH_USER_DATA != 0 alloc_option->allocator.user_data, #endif @@ -151,16 +515,58 @@ wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, } else if (mem_alloc_type == Alloc_With_System_Allocator) { memory_mode = MEMORY_MODE_SYSTEM_ALLOCATOR; - return true; + ret = true; } else { - return false; + ret = false; } + +#if WASM_ENABLE_SHARED_HEAP != 0 + if (!ret) { + os_mutex_destroy(&shared_heap_list_lock); + } +#endif + + return ret; } -void -wasm_runtime_memory_destroy() +#if WASM_ENABLE_SHARED_HEAP != 0 +static void +destroy_shared_heaps() { + WASMSharedHeap *heap; + WASMSharedHeap *cur; + uint64 map_size; + + os_mutex_lock(&shared_heap_list_lock); + heap = shared_heap_list; + shared_heap_list = NULL; + os_mutex_unlock(&shared_heap_list_lock); + + while (heap) { + cur = heap; + heap = heap->next; + mem_allocator_destroy(cur->heap_handle); + wasm_runtime_free(cur->heap_handle); +#ifndef OS_ENABLE_HW_BOUND_CHECK + map_size = cur->size; +#else + map_size = 8 * (uint64)BH_GB; +#endif + wasm_munmap_linear_memory(cur->base_addr, cur->size, map_size); + wasm_runtime_free(cur); + } + os_mutex_destroy(&shared_heap_list_lock); +} +#endif + +void +wasm_runtime_memory_destroy(void) +{ +#if WASM_ENABLE_SHARED_HEAP != 0 + destroy_shared_heaps(); +#endif + if (memory_mode == MEMORY_MODE_POOL) { #if BH_ENABLE_GC_VERIFY == 0 (void)mem_allocator_destroy(pool_allocator); @@ -176,7 +582,7 @@ wasm_runtime_memory_destroy() } unsigned -wasm_runtime_memory_pool_size() +wasm_runtime_memory_pool_size(void) { if (memory_mode == MEMORY_MODE_POOL) return global_pool_size; @@ -335,6 +741,13 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm, goto fail; } +#if WASM_ENABLE_SHARED_HEAP != 0 + if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64, + app_offset, size)) { + return true; + } +#endif + #if WASM_ENABLE_MEMORY64 != 0 if (memory_inst->is_memory64) max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; @@ -364,6 +777,7 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm, uint64 app_str_offset) { WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; uint64 app_end_offset, max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE; char *str, *str_end; @@ -374,22 +788,42 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm, return true; } - if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, NULL, - &app_end_offset)) + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { goto fail; + } + +#if WASM_ENABLE_SHARED_HEAP != 0 + if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64, + app_str_offset, 1)) { + WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm); + str = (char *)shared_heap->base_addr + + (memory_inst->is_memory64 + ? (app_str_offset - shared_heap->start_off_mem64) + : (app_str_offset - shared_heap->start_off_mem32)); + str_end = (char *)shared_heap->base_addr + shared_heap->size; + } + else +#endif + { + if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, + NULL, &app_end_offset)) + goto fail; #if WASM_ENABLE_MEMORY64 != 0 - if (module_inst->memories[0]->is_memory64) - max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; + if (memory_inst->is_memory64) + max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; #endif - /* boundary overflow check, max start offset can only be size - 1, while end - * offset can be size */ - if (app_str_offset >= max_linear_memory_size - || app_end_offset > max_linear_memory_size) - goto fail; + /* boundary overflow check, max start offset can be size - 1, while end + offset can be size */ + if (app_str_offset >= max_linear_memory_size + || app_end_offset > max_linear_memory_size) + goto fail; + + str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset); + str_end = str + (app_end_offset - app_str_offset); + } - str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset); - str_end = str + (app_end_offset - app_str_offset); while (str < str_end && *str != '\0') str++; if (str == str_end) @@ -431,6 +865,12 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm, goto fail; } +#if WASM_ENABLE_SHARED_HEAP != 0 + if (is_native_addr_in_shared_heap(module_inst_comm, native_ptr, size)) { + return true; + } +#endif + SHARED_MEMORY_LOCK(memory_inst); if (memory_inst->memory_data <= addr @@ -465,6 +905,23 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm, return NULL; } +#if WASM_ENABLE_SHARED_HEAP != 0 + if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64, + app_offset, 1)) { + WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm); + uint64 shared_heap_start = 0; + + if (memory_inst && !memory_inst->is_memory64) { + shared_heap_start = shared_heap->start_off_mem32; + } + else if (memory_inst && memory_inst->is_memory64) { + shared_heap_start = shared_heap->start_off_mem64; + } + + return shared_heap->base_addr + app_offset - shared_heap_start; + } +#endif + SHARED_MEMORY_LOCK(memory_inst); addr = memory_inst->memory_data + (uintptr_t)app_offset; @@ -499,11 +956,32 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm, bounds_checks = is_bounds_checks_enabled(module_inst_comm); +#if WASM_ENABLE_SHARED_HEAP != 0 + /* If shared heap is enabled, bounds check is always needed */ + bounds_checks = true; +#endif + memory_inst = wasm_get_default_memory(module_inst); if (!memory_inst) { return 0; } +#if WASM_ENABLE_SHARED_HEAP != 0 + if (is_native_addr_in_shared_heap(module_inst_comm, addr, 1)) { + WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm); + uint64 shared_heap_start = 0; + + if (memory_inst && !memory_inst->is_memory64) { + shared_heap_start = shared_heap->start_off_mem32; + } + else if (memory_inst && memory_inst->is_memory64) { + shared_heap_start = shared_heap->start_off_mem64; + } + + return shared_heap_start + (addr - shared_heap->base_addr); + } +#endif + SHARED_MEMORY_LOCK(memory_inst); if (bounds_checks) { @@ -601,6 +1079,10 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst); uint8 *native_addr; bool bounds_checks; +#if WASM_ENABLE_SHARED_HEAP != 0 + WASMSharedHeap *shared_heap; + bool is_in_shared_heap = false; +#endif bh_assert(app_buf_addr <= UINTPTR_MAX && app_buf_size <= UINTPTR_MAX); @@ -609,9 +1091,25 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, return false; } - native_addr = memory_inst->memory_data + (uintptr_t)app_buf_addr; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (is_app_addr_in_shared_heap((WASMModuleInstanceCommon *)module_inst, + memory_inst->is_memory64, app_buf_addr, + app_buf_size)) { + shared_heap = get_shared_heap((WASMModuleInstanceCommon *)module_inst); + native_addr = shared_heap->base_addr + + (memory_inst->is_memory64 + ? (app_buf_addr - shared_heap->start_off_mem64) + : (app_buf_addr - shared_heap->start_off_mem32)); + is_in_shared_heap = true; + } + else +#endif + { + native_addr = memory_inst->memory_data + (uintptr_t)app_buf_addr; + } - bounds_checks = is_bounds_checks_enabled((wasm_module_inst_t)module_inst); + bounds_checks = + is_bounds_checks_enabled((WASMModuleInstanceCommon *)module_inst); if (!bounds_checks) { if (app_buf_addr == 0) { @@ -620,6 +1118,24 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, goto success; } +#if WASM_ENABLE_SHARED_HEAP != 0 + if (is_in_shared_heap) { + const char *str, *str_end; + + /* The whole string must be in the linear memory */ + str = (const char *)native_addr; + str_end = (const char *)shared_heap->base_addr + shared_heap->size; + while (str < str_end && *str != '\0') + str++; + if (str == str_end) { + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; + } + else + goto success; + } +#endif + /* No need to check the app_offset and buf_size if memory access boundary check with hardware trap is enabled */ #ifndef OS_ENABLE_HW_BOUND_CHECK @@ -673,11 +1189,9 @@ wasm_get_default_memory(WASMModuleInstance *module_inst) WASMMemoryInstance * wasm_get_memory_with_idx(WASMModuleInstance *module_inst, uint32 index) { - bh_assert(index < module_inst->memory_count); - if (module_inst->memories) - return module_inst->memories[index]; - else + if ((index >= module_inst->memory_count) || !module_inst->memories) return NULL; + return module_inst->memories[index]; } void @@ -751,19 +1265,17 @@ wasm_mremap_linear_memory(void *mapped_mem, uint64 old_size, uint64 new_size, } static void * -wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size) +wasm_mmap_linear_memory(uint64 map_size, uint64 commit_size) { return wasm_mremap_linear_memory(NULL, 0, map_size, commit_size); } -bool -wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count, - uint32 memidx) +static bool +wasm_enlarge_memory_internal(WASMModuleInstanceCommon *module, + WASMMemoryInstance *memory, uint32 inc_page_count) { -#if WASM_ENABLE_MULTI_MEMORY != 0 - WASMMemoryInstance *memory = wasm_get_memory_with_idx(module, memidx); -#else - WASMMemoryInstance *memory = wasm_get_default_memory(module); +#if WASM_ENABLE_SHARED_HEAP != 0 + WASMSharedHeap *shared_heap; #endif uint8 *memory_data_old, *memory_data_new, *heap_data_old; uint32 num_bytes_per_page, heap_size; @@ -812,6 +1324,24 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count, goto return_func; } +#if WASM_ENABLE_SHARED_HEAP != 0 + shared_heap = get_shared_heap(module); + if (shared_heap) { + if (memory->is_memory64 + && total_size_new > shared_heap->start_off_mem64) { + LOG_WARNING("Linear memory address is overlapped with shared heap"); + ret = false; + goto return_func; + } + else if (!memory->is_memory64 + && total_size_new > shared_heap->start_off_mem32) { + LOG_WARNING("Linear memory address is overlapped with shared heap"); + ret = false; + goto return_func; + } + } +#endif + bh_assert(total_size_new <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)); @@ -913,7 +1443,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count, wasm_runtime_set_mem_bound_check_bytes(memory, total_size_new); return_func: - if (!ret && enlarge_memory_error_cb) { + if (!ret && module && enlarge_memory_error_cb) { WASMExecEnv *exec_env = NULL; #if WASM_ENABLE_INTERP != 0 @@ -926,8 +1456,7 @@ return_func: #endif enlarge_memory_error_cb(inc_page_count, total_size_old, 0, - failure_reason, - (WASMModuleInstanceCommon *)module, exec_env, + failure_reason, module, exec_env, enlarge_memory_error_user_data); } @@ -971,15 +1500,16 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) { bool ret = false; + if (module->memory_count > 0) { #if WASM_ENABLE_SHARED_MEMORY != 0 - if (module->memory_count > 0) shared_memory_lock(module->memories[0]); #endif - ret = wasm_enlarge_memory_internal(module, inc_page_count, 0); + ret = wasm_enlarge_memory_internal((WASMModuleInstanceCommon *)module, + module->memories[0], inc_page_count); #if WASM_ENABLE_SHARED_MEMORY != 0 - if (module->memory_count > 0) shared_memory_unlock(module->memories[0]); #endif + } return ret; } @@ -990,15 +1520,117 @@ wasm_enlarge_memory_with_idx(WASMModuleInstance *module, uint32 inc_page_count, { bool ret = false; + if (memidx < module->memory_count) { #if WASM_ENABLE_SHARED_MEMORY != 0 - if (memidx < module->memory_count) shared_memory_lock(module->memories[memidx]); #endif - ret = wasm_enlarge_memory_internal(module, inc_page_count, memidx); + ret = wasm_enlarge_memory_internal((WASMModuleInstanceCommon *)module, + module->memories[memidx], + inc_page_count); #if WASM_ENABLE_SHARED_MEMORY != 0 - if (memidx < module->memory_count) shared_memory_unlock(module->memories[memidx]); #endif + } + + return ret; +} + +WASMMemoryInstance * +wasm_runtime_lookup_memory(WASMModuleInstanceCommon *module_inst, + const char *name) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_lookup_memory((WASMModuleInstance *)module_inst, name); +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_lookup_memory((WASMModuleInstance *)module_inst, name); +#endif + + return NULL; +} + +WASMMemoryInstance * +wasm_runtime_get_default_memory(WASMModuleInstanceCommon *module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_get_default_memory((WASMModuleInstance *)module_inst); +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_get_default_memory((AOTModuleInstance *)module_inst); +#endif + + return NULL; +} + +WASMMemoryInstance * +wasm_runtime_get_memory(WASMModuleInstanceCommon *module_inst, uint32 index) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_get_memory_with_idx((WASMModuleInstance *)module_inst, + index); +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_get_memory_with_index((AOTModuleInstance *)module_inst, + index); +#endif + + return NULL; +} + +uint64 +wasm_memory_get_cur_page_count(WASMMemoryInstance *memory) +{ + return memory->cur_page_count; +} + +uint64 +wasm_memory_get_max_page_count(WASMMemoryInstance *memory) +{ + return memory->max_page_count; +} + +uint64 +wasm_memory_get_bytes_per_page(WASMMemoryInstance *memory) +{ + return memory->num_bytes_per_page; +} + +bool +wasm_memory_get_shared(WASMMemoryInstance *memory) +{ + return memory->is_shared_memory; +} + +void * +wasm_memory_get_base_address(WASMMemoryInstance *memory) +{ + return memory->memory_data; +} + +bool +wasm_memory_enlarge(WASMMemoryInstance *memory, uint64 inc_page_count) +{ + bool ret = false; + + if (memory) { +#if WASM_ENABLE_SHARED_MEMORY != 0 + shared_memory_lock(memory); +#endif + ret = + wasm_enlarge_memory_internal(NULL, memory, (uint32)inc_page_count); +#if WASM_ENABLE_SHARED_MEMORY != 0 + shared_memory_unlock(memory); +#endif + } return ret; } diff --git a/core/iwasm/common/wasm_memory.h b/core/iwasm/common/wasm_memory.h index a5dfefae9..bceea0ee4 100644 --- a/core/iwasm/common/wasm_memory.h +++ b/core/iwasm/common/wasm_memory.h @@ -41,15 +41,44 @@ SET_LINEAR_MEMORY_SIZE(WASMMemoryInstance *memory, uint64 size) #define SET_LINEAR_MEMORY_SIZE(memory, size) memory->memory_data_size = size #endif +#if WASM_ENABLE_SHARED_HEAP != 0 +WASMSharedHeap * +wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args); + +bool +wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst, + WASMSharedHeap *shared_heap); +bool +wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst, + WASMSharedHeap *shared_heap); + +void +wasm_runtime_detach_shared_heap(WASMModuleInstanceCommon *module_inst); + +void +wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst); + +WASMSharedHeap * +wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm); + +uint64 +wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst, + uint64 size, void **p_native_addr); + +void +wasm_runtime_shared_heap_free(WASMModuleInstanceCommon *module_inst, + uint64 ptr); +#endif + bool wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, const MemAllocOption *alloc_option); void -wasm_runtime_memory_destroy(); +wasm_runtime_memory_destroy(void); unsigned -wasm_runtime_memory_pool_size(); +wasm_runtime_memory_pool_size(void); void wasm_runtime_set_mem_bound_check_bytes(WASMMemoryInstance *memory, diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 9e8764a22..060bb2c3d 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -33,6 +33,11 @@ uint32 get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis); #endif +#if WASM_ENABLE_SHARED_HEAP != 0 +uint32 +get_lib_shared_heap_export_apis(NativeSymbol **p_shared_heap_apis); +#endif + uint32 get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis); @@ -469,7 +474,7 @@ wasi_context_dtor(WASMModuleInstanceCommon *inst, void *ctx) #if WASM_ENABLE_QUICK_AOT_ENTRY != 0 static bool -quick_aot_entry_init(); +quick_aot_entry_init(void); #endif bool @@ -512,6 +517,14 @@ wasm_native_init() goto fail; #endif +#if WASM_ENABLE_SHARED_HEAP != 0 + n_native_symbols = get_lib_shared_heap_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("env", native_symbols, + n_native_symbols)) + goto fail; +#endif + #if WASM_ENABLE_BASE_LIB != 0 n_native_symbols = get_base_lib_export_apis(&native_symbols); if (n_native_symbols > 0 @@ -1461,7 +1474,7 @@ quick_aot_entry_cmp(const void *quick_aot_entry1, const void *quick_aot_entry2) } static bool -quick_aot_entry_init() +quick_aot_entry_init(void) { qsort(quick_aot_entries, sizeof(quick_aot_entries) / sizeof(QuickAOTEntry), sizeof(QuickAOTEntry), quick_aot_entry_cmp); diff --git a/core/iwasm/common/wasm_native.h b/core/iwasm/common/wasm_native.h index 5cb78bf91..9a6afee19 100644 --- a/core/iwasm/common/wasm_native.h +++ b/core/iwasm/common/wasm_native.h @@ -100,10 +100,10 @@ wasm_native_inherit_contexts(struct WASMModuleInstanceCommon *child, #endif /* WASM_ENABLE_MODULE_INST_CONTEXT */ bool -wasm_native_init(); +wasm_native_init(void); void -wasm_native_destroy(); +wasm_native_destroy(void); #if WASM_ENABLE_QUICK_AOT_ENTRY != 0 void * diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 5dd2957de..fb16aa0f3 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -86,7 +86,7 @@ static bh_list registered_module_list_head; static bh_list *const registered_module_list = ®istered_module_list_head; static korp_mutex registered_module_list_lock; static void -wasm_runtime_destroy_registered_module_list(); +wasm_runtime_destroy_registered_module_list(void); #endif /* WASM_ENABLE_MULTI_MODULE */ #define E_TYPE_XIP 4 @@ -97,11 +97,11 @@ val_type_to_val_kind(uint8 value_type); #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 /* Initialize externref hashmap */ static bool -wasm_externref_map_init(); +wasm_externref_map_init(void); /* Destroy externref hashmap */ static void -wasm_externref_map_destroy(); +wasm_externref_map_destroy(void); #endif /* end of WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 */ static void @@ -185,6 +185,9 @@ static bool is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst) { WASMMemoryInstance *memory_inst; +#if WASM_ENABLE_SHARED_HEAP != 0 + WASMSharedHeap *shared_heap; +#endif uint8 *mapped_mem_start_addr = NULL; uint8 *mapped_mem_end_addr = NULL; uint32 i; @@ -202,6 +205,21 @@ is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst) } } +#if WASM_ENABLE_SHARED_HEAP != 0 + shared_heap = + wasm_runtime_get_shared_heap((WASMModuleInstanceCommon *)module_inst); + if (shared_heap) { + mapped_mem_start_addr = shared_heap->base_addr; + mapped_mem_end_addr = shared_heap->base_addr + 8 * (uint64)BH_GB; + if (mapped_mem_start_addr <= (uint8 *)sig_addr + && (uint8 *)sig_addr < mapped_mem_end_addr) { + /* The address which causes segmentation fault is inside + the shared heap's guard regions */ + return true; + } + } +#endif + return false; } @@ -340,7 +358,6 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info) PEXCEPTION_RECORD ExceptionRecord = exce_info->ExceptionRecord; uint8 *sig_addr = (uint8 *)ExceptionRecord->ExceptionInformation[1]; WASMModuleInstance *module_inst; - WASMMemoryInstance *memory_inst; WASMJmpBuf *jmpbuf_node; uint8 *mapped_mem_start_addr = NULL; uint8 *mapped_mem_end_addr = NULL; @@ -438,7 +455,7 @@ wasm_runtime_get_exec_env_tls() #endif /* end of OS_ENABLE_HW_BOUND_CHECK */ static bool -wasm_runtime_env_init() +wasm_runtime_env_init(void) { if (bh_platform_init() != 0) return false; @@ -584,7 +601,7 @@ static korp_mutex runtime_lock = OS_THREAD_MUTEX_INITIALIZER; static int32 runtime_ref_count = 0; static bool -wasm_runtime_init_internal() +wasm_runtime_init_internal(void) { if (!wasm_runtime_memory_init(Alloc_With_System_Allocator, NULL)) return false; @@ -622,7 +639,7 @@ wasm_runtime_init() } static void -wasm_runtime_destroy_internal() +wasm_runtime_destroy_internal(void) { #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 wasm_externref_map_destroy(); @@ -1484,6 +1501,22 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args, error_buf_size); } +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_resolve_symbols(WASMModuleCommon *module) +{ +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) { + return wasm_resolve_symbols((WASMModule *)module); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) { + return aot_resolve_symbols((AOTModule *)module); + } +#endif + return false; +} + WASMModuleCommon * wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size) @@ -2192,6 +2225,13 @@ wasm_runtime_get_user_data(WASMExecEnv *exec_env) return exec_env->user_data; } +void +wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env, + uint8 *native_stack_boundary) +{ + exec_env->user_native_stack_boundary = native_stack_boundary; +} + #ifdef OS_ENABLE_HW_BOUND_CHECK void wasm_runtime_access_exce_check_guard_page() @@ -3577,7 +3617,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, char mapping_copy_buf[256]; char *mapping_copy = mapping_copy_buf; char *map_mapped = NULL, *map_host = NULL; - const unsigned long max_len = strlen(map_dir_list[i]) * 2 + 3; + const unsigned long max_len = + (unsigned long)strlen(map_dir_list[i]) * 2 + 3; /* Allocation limit for runtime environments with reduced stack size */ if (max_len > 256) { @@ -3867,23 +3908,18 @@ wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst) WASMFunctionInstanceCommon * wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst) { - uint32 i; - #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst; - WASMFunctionInstance *func; - for (i = 0; i < wasm_inst->export_func_count; i++) { - if (!strcmp(wasm_inst->export_functions[i].name, "_start")) { - func = wasm_inst->export_functions[i].function; - if (func->u.func->func_type->param_count != 0 - || func->u.func->func_type->result_count != 0) { - LOG_ERROR("Lookup wasi _start function failed: " - "invalid function type.\n"); - return NULL; - } - return (WASMFunctionInstanceCommon *)func; + WASMFunctionInstance *func = wasm_lookup_function(wasm_inst, "_start"); + if (func) { + if (func->u.func->func_type->param_count != 0 + || func->u.func->func_type->result_count != 0) { + LOG_ERROR("Lookup wasi _start function failed: " + "invalid function type.\n"); + return NULL; } + return (WASMFunctionInstanceCommon *)func; } return NULL; } @@ -3892,19 +3928,15 @@ wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst) #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst; - AOTFunctionInstance *export_funcs = - (AOTFunctionInstance *)aot_inst->export_functions; - for (i = 0; i < aot_inst->export_func_count; i++) { - if (!strcmp(export_funcs[i].func_name, "_start")) { - AOTFuncType *func_type = export_funcs[i].u.func.func_type; - if (func_type->param_count != 0 - || func_type->result_count != 0) { - LOG_ERROR("Lookup wasi _start function failed: " - "invalid function type.\n"); - return NULL; - } - return (WASMFunctionInstanceCommon *)&export_funcs[i]; + AOTFunctionInstance *func = aot_lookup_function(aot_inst, "_start"); + if (func) { + AOTFuncType *func_type = func->u.func.func_type; + if (func_type->param_count != 0 || func_type->result_count != 0) { + LOG_ERROR("Lookup wasi _start function failed: " + "invalid function type.\n"); + return NULL; } + return func; } return NULL; } @@ -4498,9 +4530,14 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, uint32 *argv, uint32 argc, uint32 *argv_ret) { WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); +#if WASM_ENABLE_MEMORY64 != 0 + WASMMemoryInstance *memory = + wasm_get_default_memory((WASMModuleInstance *)module); + bool is_memory64 = memory ? memory->is_memory64 : false; +#endif typedef void (*NativeRawFuncPtr)(WASMExecEnv *, uint64 *); NativeRawFuncPtr invoke_native_raw = (NativeRawFuncPtr)func_ptr; - uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size, arg_i64; + uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size; uint32 *argv_src = argv, i, argc1, ptr_len; uint32 arg_i32; bool ret = false; @@ -4525,11 +4562,11 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, #endif { *(uint32 *)argv_dst = arg_i32 = *argv_src++; - /* TODO: memory64 if future there is a way for supporting - * wasm64 and wasm32 in libc at the same time, remove the - * macro control */ -#if WASM_ENABLE_MEMORY64 == 0 - if (signature) { + if (signature +#if WASM_ENABLE_MEMORY64 != 0 + && !is_memory64 +#endif + ) { if (signature[i + 1] == '*') { /* param is a pointer */ if (signature[i + 2] == '~') @@ -4558,17 +4595,18 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, module, (uint64)arg_i32); } } -#endif break; } case VALUE_TYPE_I64: #if WASM_ENABLE_MEMORY64 != 0 { + uint64 arg_i64; + PUT_I64_TO_ADDR((uint32 *)argv_dst, GET_I64_FROM_ADDR(argv_src)); argv_src += 2; arg_i64 = *argv_dst; - if (signature) { + if (signature && is_memory64) { /* TODO: memory64 pointer with length need a new symbol * to represent type i64, with '~' still represent i32 * length */ @@ -4729,9 +4767,6 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, fail: if (argv1 != argv_buf) wasm_runtime_free(argv1); -#if WASM_ENABLE_MEMORY64 == 0 - (void)arg_i64; -#endif return ret; } @@ -4747,7 +4782,7 @@ fail: || defined(BUILD_TARGET_RISCV32_ILP32D) \ || defined(BUILD_TARGET_RISCV32_ILP32F) \ || defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) -typedef void (*GenericFunctionPointer)(); +typedef void (*GenericFunctionPointer)(void); void invokeNative(GenericFunctionPointer f, uint32 *args, uint32 n_stacks); @@ -5312,7 +5347,7 @@ fail: #if defined(BUILD_TARGET_X86_32) || defined(BUILD_TARGET_ARM) \ || defined(BUILD_TARGET_THUMB) || defined(BUILD_TARGET_MIPS) \ || defined(BUILD_TARGET_XTENSA) -typedef void (*GenericFunctionPointer)(); +typedef void (*GenericFunctionPointer)(void); void invokeNative(GenericFunctionPointer f, uint32 *args, uint32 sz); @@ -5597,7 +5632,7 @@ typedef uint32x4_t __m128i; #endif /* end of WASM_ENABLE_SIMD != 0 */ -typedef void (*GenericFunctionPointer)(); +typedef void (*GenericFunctionPointer)(void); void invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks); @@ -5655,6 +5690,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 *argv_ret) { WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); +#if WASM_ENABLE_MEMORY64 != 0 + WASMMemoryInstance *memory = + wasm_get_default_memory((WASMModuleInstance *)module); + bool is_memory64 = memory ? memory->is_memory64 : false; +#endif uint64 argv_buf[32] = { 0 }, *argv1 = argv_buf, *ints, *stacks, size, arg_i64; uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; @@ -5720,11 +5760,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { arg_i32 = *argv_src++; arg_i64 = arg_i32; - /* TODO: memory64 if future there is a way for supporting - * wasm64 and wasm32 in libc at the same time, remove the - * macro control */ -#if WASM_ENABLE_MEMORY64 == 0 - if (signature) { + if (signature +#if WASM_ENABLE_MEMORY64 != 0 + && !is_memory64 +#endif + ) { if (signature[i + 1] == '*') { /* param is a pointer */ if (signature[i + 2] == '~') @@ -5751,7 +5791,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, module, (uint64)arg_i32); } } -#endif if (n_ints < MAX_REG_INTS) ints[n_ints++] = arg_i64; else @@ -5763,7 +5802,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { arg_i64 = GET_I64_FROM_ADDR(argv_src); argv_src += 2; - if (signature) { + if (signature && is_memory64) { /* TODO: memory64 pointer with length need a new symbol * to represent type i64, with '~' still represent i32 * length */ diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 71264ca7e..4c7dfed4f 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -673,6 +673,11 @@ wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data); WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_user_data(WASMExecEnv *exec_env); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env, + uint8 *native_stack_boundary); + #if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0 /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN void @@ -852,10 +857,10 @@ wasm_runtime_set_module_reader(const module_reader reader, const module_destroyer destroyer); module_reader -wasm_runtime_get_module_reader(); +wasm_runtime_get_module_reader(void); module_destroyer -wasm_runtime_get_module_destroyer(); +wasm_runtime_get_module_destroyer(void); bool wasm_runtime_register_module_internal(const char *module_name, @@ -881,7 +886,7 @@ bool wasm_runtime_is_loading_module(const char *module_name); void -wasm_runtime_destroy_loading_module_list(); +wasm_runtime_destroy_loading_module_list(void); WASMModuleCommon * wasm_runtime_search_sub_module(const WASMModuleCommon *parent_module, @@ -1168,7 +1173,7 @@ wasm_runtime_quick_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, uint32 result_count); void -wasm_runtime_show_app_heap_corrupted_prompt(); +wasm_runtime_show_app_heap_corrupted_prompt(void); #if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 void diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 9cfdd0926..2027a5720 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -8,6 +8,9 @@ #if WASM_ENABLE_THREAD_MGR != 0 #include "../libraries/thread-mgr/thread_manager.h" #endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#endif /* * Note: this lock can be per memory. @@ -243,6 +246,31 @@ map_try_release_wait_info(HashMap *wait_hash_map, AtomicWaitInfo *wait_info, destroy_wait_info(wait_info); } +#if WASM_ENABLE_SHARED_HEAP != 0 +static bool +is_native_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst, + uint8 *addr, uint32 bytes) +{ + WASMSharedHeap *shared_heap = NULL; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + shared_heap = ((WASMModuleInstance *)module_inst)->e->shared_heap; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e; + shared_heap = e->shared_heap; + } +#endif + + return shared_heap && addr >= shared_heap->base_addr + && addr + bytes <= shared_heap->base_addr + shared_heap->size; +} +#endif + uint32 wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, uint64 expect, int64 timeout, bool wait64) @@ -271,9 +299,17 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, } shared_memory_lock(module_inst->memories[0]); - if ((uint8 *)address < module_inst->memories[0]->memory_data - || (uint8 *)address + (wait64 ? 8 : 4) - > module_inst->memories[0]->memory_data_end) { + if ( +#if WASM_ENABLE_SHARED_HEAP != 0 + /* not in shared heap */ + !is_native_addr_in_shared_heap((WASMModuleInstanceCommon *)module_inst, + address, wait64 ? 8 : 4) + && +#endif + /* and not in linear memory */ + ((uint8 *)address < module_inst->memories[0]->memory_data + || (uint8 *)address + (wait64 ? 8 : 4) + > module_inst->memories[0]->memory_data_end)) { shared_memory_unlock(module_inst->memories[0]); wasm_runtime_set_exception(module, "out of bounds memory access"); return -1; @@ -397,6 +433,11 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, shared_memory_lock(module_inst->memories[0]); out_of_bounds = +#if WASM_ENABLE_SHARED_HEAP != 0 + /* not in shared heap */ + !is_native_addr_in_shared_heap(module, address, 4) && +#endif + /* and not in linear memory */ ((uint8 *)address < module_inst->memories[0]->memory_data || (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end); shared_memory_unlock(module_inst->memories[0]); diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h index 8bbc4a800..e1c5154a5 100644 --- a/core/iwasm/common/wasm_shared_memory.h +++ b/core/iwasm/common/wasm_shared_memory.h @@ -17,10 +17,10 @@ extern "C" { extern korp_mutex g_shared_memory_lock; bool -wasm_shared_memory_init(); +wasm_shared_memory_init(void); void -wasm_shared_memory_destroy(); +wasm_shared_memory_destroy(void); uint16 shared_memory_inc_reference(WASMMemoryInstance *memory); diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index dcf9bbe12..98d2cc6cc 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -312,7 +312,7 @@ void aot_destroy_comp_data(AOTCompData *comp_data); char * -aot_get_last_error(); +aot_get_last_error(void); void aot_set_last_error(const char *error); diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 96ed8facf..07734b3b4 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -16,6 +16,7 @@ #include "aot_emit_parametric.h" #include "aot_emit_table.h" #include "aot_emit_gc.h" +#include "aot_stack_frame_comp.h" #include "simd/simd_access_lanes.h" #include "simd/simd_bitmask_extracts.h" #include "simd/simd_bit_shifts.h" @@ -145,9 +146,20 @@ aot_validate_wasm(AOTCompContext *comp_ctx) } #if WASM_ENABLE_MEMORY64 != 0 - if (comp_ctx->pointer_size < sizeof(uint64) && IS_MEMORY64) { - aot_set_last_error("Compiling wasm64 to 32bit platform is not allowed"); - return false; + if (comp_ctx->pointer_size < sizeof(uint64)) { + if (IS_MEMORY64) { + aot_set_last_error("Compiling wasm64(contains i64 memory section) " + "to 32bit platform is not allowed"); + return false; + } + + for (uint32 i = 0; i < comp_ctx->comp_data->table_count; ++i) { + if (IS_TABLE64(i)) { + aot_set_last_error("Compiling wasm64(contains i64 table " + "section) to 32bit platform is not allowed"); + return false; + } + } } #endif @@ -253,6 +265,13 @@ store_value(AOTCompContext *comp_ctx, LLVMValueRef value, uint8 value_type, return true; } +void +aot_call_stack_features_init_default(AOTCallStackFeatures *features) +{ + memset(features, 1, sizeof(AOTCallStackFeatures)); + features->frame_per_function = false; +} + bool aot_frame_store_value(AOTCompContext *comp_ctx, LLVMValueRef value, uint8 value_type, LLVMValueRef cur_frame, uint32 offset) @@ -337,6 +356,10 @@ aot_gen_commit_values(AOTCompFrame *frame) LLVMValueRef value; uint32 n; + if (!frame->comp_ctx->call_stack_features.values) { + return true; + } + /* First, commit reference flags * For LLVM JIT, iterate all local and stack ref flags * For AOT, ignore local(params + locals) ref flags */ @@ -569,6 +592,64 @@ aot_gen_commit_values(AOTCompFrame *frame) return true; } +static bool +aot_standard_frame_gen_commit_ip(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMValueRef ip_value, bool is_64bit) +{ + LLVMValueRef cur_frame = func_ctx->cur_frame; + LLVMValueRef value_offset, value_addr, value_ptr; + uint32 offset_ip; + + if (!comp_ctx->is_jit_mode) + offset_ip = comp_ctx->pointer_size * 4; + else + offset_ip = offsetof(WASMInterpFrame, ip); + + if (!(value_offset = I32_CONST(offset_ip))) { + aot_set_last_error("llvm build const failed"); + return false; + } + + if (!(value_addr = + LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame, + &value_offset, 1, "ip_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + + if (!(value_ptr = LLVMBuildBitCast( + comp_ctx->builder, value_addr, + is_64bit ? INT64_PTR_TYPE : INT32_PTR_TYPE, "ip_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + + if (!LLVMBuildStore(comp_ctx->builder, ip_value, value_ptr)) { + aot_set_last_error("llvm build store failed"); + return false; + } + + return true; +} + +bool +aot_gen_commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef ip_value, bool is_64bit) +{ + switch (comp_ctx->aux_stack_frame_type) { + case AOT_STACK_FRAME_TYPE_STANDARD: + return aot_standard_frame_gen_commit_ip(comp_ctx, func_ctx, + ip_value, is_64bit); + case AOT_STACK_FRAME_TYPE_TINY: + return aot_tiny_frame_gen_commit_ip(comp_ctx, func_ctx, ip_value); + default: + aot_set_last_error( + "unsupported mode when generating commit_ip code"); + return false; + } +} + bool aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip) { @@ -577,40 +658,19 @@ aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip) LLVMValueRef cur_frame = func_ctx->cur_frame; LLVMValueRef value_offset, value_addr, value_ptr, value; LLVMTypeRef int8_ptr_ptr_type; - uint32 offset_ip, offset_sp, n; + uint32 offset_sp, n; bool is_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false; const AOTValueSlot *sp = frame->sp; const uint8 *ip = frame->frame_ip; if (!comp_ctx->is_jit_mode) { - offset_ip = frame->comp_ctx->pointer_size * 4; offset_sp = frame->comp_ctx->pointer_size * 5; } else { - offset_ip = offsetof(WASMInterpFrame, ip); offset_sp = offsetof(WASMInterpFrame, sp); } - if (commit_ip) { - if (!(value_offset = I32_CONST(offset_ip))) { - aot_set_last_error("llvm build const failed"); - return false; - } - - if (!(value_addr = - LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame, - &value_offset, 1, "ip_addr"))) { - aot_set_last_error("llvm build in bounds gep failed"); - return false; - } - - if (!(value_ptr = LLVMBuildBitCast( - comp_ctx->builder, value_addr, - is_64bit ? INT64_PTR_TYPE : INT32_PTR_TYPE, "ip_ptr"))) { - aot_set_last_error("llvm build bit cast failed"); - return false; - } - + if (commit_ip && comp_ctx->call_stack_features.ip) { if (!comp_ctx->is_jit_mode) { WASMModule *module = comp_ctx->comp_data->wasm_module; if (is_64bit) @@ -630,13 +690,12 @@ aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip) return false; } - if (!LLVMBuildStore(comp_ctx->builder, value, value_ptr)) { - aot_set_last_error("llvm build store failed"); + if (!aot_gen_commit_ip(comp_ctx, func_ctx, value, is_64bit)) { return false; } } - if (commit_sp) { + if (commit_sp && comp_ctx->call_stack_features.values) { n = (uint32)(sp - frame->lp); value = I32_CONST(offset_of_local(comp_ctx, n)); if (!value) { @@ -940,6 +999,7 @@ static bool aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) { AOTFuncContext *func_ctx = comp_ctx->func_ctxes[func_index]; + LLVMValueRef func_index_ref; uint8 *frame_ip = func_ctx->aot_func->code, opcode, *p_f32, *p_f64; uint8 *frame_ip_end = frame_ip + func_ctx->aot_func->code_size; uint8 *param_types = NULL; @@ -962,16 +1022,27 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) LLVMMetadataRef location; #endif - if (comp_ctx->enable_aux_stack_frame) { + /* Start to translate the opcodes */ + LLVMPositionBuilderAtEnd( + comp_ctx->builder, + func_ctx->block_stack.block_list_head->llvm_entry_block); + + if (comp_ctx->aux_stack_frame_type + && comp_ctx->call_stack_features.frame_per_function) { + INT_CONST(func_index_ref, + func_index + comp_ctx->comp_data->import_func_count, I32_TYPE, + true); + if (!aot_alloc_frame_per_function_frame_for_aot_func(comp_ctx, func_ctx, + func_index_ref)) { + return false; + } + } + if (comp_ctx->aux_stack_frame_type) { if (!init_comp_frame(comp_ctx, func_ctx, func_index)) { return false; } } - /* Start to translate the opcodes */ - LLVMPositionBuilderAtEnd( - comp_ctx->builder, - func_ctx->block_stack.block_list_head->llvm_entry_block); while (frame_ip < frame_ip_end) { opcode = *frame_ip++; diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index ab74b7cb6..06d8e42bd 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -195,6 +195,15 @@ aot_gen_commit_values(AOTCompFrame *frame); bool aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip); +/** + * Generate instructions to commit IP pointer to the frame. + * + * @param frame the frame information + */ +bool +aot_gen_commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef ip_value, bool is_64bit); + bool aot_frame_store_value(AOTCompContext *comp_ctx, LLVMValueRef value, uint8 value_type, LLVMValueRef cur_frame, uint32 offset); @@ -523,8 +532,13 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type) #define IS_MEMORY64 (comp_ctx->comp_data->memories[0].flags & MEMORY64_FLAG) #define MEMORY64_COND_VALUE(VAL_IF_ENABLED, VAL_IF_DISABLED) \ (IS_MEMORY64 ? VAL_IF_ENABLED : VAL_IF_DISABLED) +#define IS_TABLE64(i) \ + (comp_ctx->comp_data->tables[i].table_type.flags & TABLE64_FLAG) +#define TABLE64_COND_VALUE(i, VAL_IF_ENABLED, VAL_IF_DISABLED) \ + (IS_TABLE64(i) ? VAL_IF_ENABLED : VAL_IF_DISABLED) #else #define MEMORY64_COND_VALUE(VAL_IF_ENABLED, VAL_IF_DISABLED) (VAL_IF_DISABLED) +#define TABLE64_COND_VALUE(i, VAL_IF_ENABLED, VAL_IF_DISABLED) (VAL_IF_DISABLED) #endif #define POP_I32(v) POP(v, VALUE_TYPE_I32) @@ -539,6 +553,9 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type) POP(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32)) #define POP_PAGE_COUNT(v) \ POP(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32)) +#define POP_TBL_ELEM_IDX(v) \ + POP(v, TABLE64_COND_VALUE(tbl_idx, VALUE_TYPE_I64, VALUE_TYPE_I32)) +#define POP_TBL_ELEM_LEN(v) POP_TBL_ELEM_IDX(v) #define POP_COND(llvm_value) \ do { \ @@ -604,6 +621,9 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type) #define PUSH_GC_REF(v) PUSH(v, VALUE_TYPE_GC_REF) #define PUSH_PAGE_COUNT(v) \ PUSH(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32)) +#define PUSH_TBL_ELEM_IDX(v) \ + PUSH(v, TABLE64_COND_VALUE(tbl_idx, VALUE_TYPE_I64, VALUE_TYPE_I32)) +#define PUSH_TBL_ELEM_LEN(v) PUSH_TBL_ELEM_IDX(v) #define SET_CONST(v) \ do { \ @@ -652,6 +672,15 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type) #define F64_CONST(v) LLVMConstReal(F64_TYPE, v) #define I8_CONST(v) LLVMConstInt(INT8_TYPE, v, true) +#define INT_CONST(variable, value, type, is_signed) \ + do { \ + variable = LLVMConstInt(type, value, is_signed); \ + if (!variable) { \ + aot_set_last_error("llvm build const failed"); \ + return false; \ + } \ + } while (0) + #define LLVM_CONST(name) (comp_ctx->llvm_consts.name) #define I1_ZERO LLVM_CONST(i1_zero) #define I1_ONE LLVM_CONST(i1_one) diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index e05f83b09..8fa205308 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -4433,6 +4433,15 @@ aot_obj_data_create(AOTCompContext *comp_ctx) if (comp_ctx->enable_gc) { obj_data->target_info.feature_flags |= WASM_FEATURE_GARBAGE_COLLECTION; } + if (comp_ctx->aux_stack_frame_type == AOT_STACK_FRAME_TYPE_TINY) { + obj_data->target_info.feature_flags |= WASM_FEATURE_TINY_STACK_FRAME; + } + if (comp_ctx->call_stack_features.frame_per_function) { + obj_data->target_info.feature_flags |= WASM_FEATURE_FRAME_PER_FUNCTION; + } + if (!comp_ctx->call_stack_features.func_idx) { + obj_data->target_info.feature_flags |= WASM_FEATURE_FRAME_NO_FUNC_IDX; + } bh_print_time("Begin to resolve object file info"); diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 7d73d8d90..1c50fe75f 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -6,6 +6,7 @@ #include "aot_emit_control.h" #include "aot_compiler.h" #include "aot_emit_exception.h" +#include "aot_stack_frame_comp.h" #if WASM_ENABLE_GC != 0 #include "aot_emit_gc.h" #endif @@ -38,13 +39,24 @@ format_block_name(char *name, uint32 name_size, uint32 block_index, snprintf(name, name_size, "%s", "func_end"); } -#define CREATE_BLOCK(new_llvm_block, name) \ - do { \ - if (!(new_llvm_block = LLVMAppendBasicBlockInContext( \ - comp_ctx->context, func_ctx->func, name))) { \ - aot_set_last_error("add LLVM basic block failed."); \ - goto fail; \ - } \ +#define CREATE_BLOCK(new_llvm_block, name) \ + do { \ + if (!(new_llvm_block = LLVMAppendBasicBlockInContext( \ + comp_ctx->context, func_ctx->func, name))) { \ + aot_set_last_error("add LLVM basic block failed."); \ + goto fail; \ + } \ + if (!strcmp(name, "func_end") && comp_ctx->aux_stack_frame_type \ + && comp_ctx->call_stack_features.frame_per_function) { \ + LLVMBasicBlockRef cur_block = \ + LLVMGetInsertBlock(comp_ctx->builder); \ + SET_BUILDER_POS(new_llvm_block); \ + if (!aot_free_frame_per_function_frame_for_aot_func(comp_ctx, \ + func_ctx)) { \ + goto fail; \ + } \ + SET_BUILDER_POS(cur_block); \ + } \ } while (0) #define CURR_BLOCK() LLVMGetInsertBlock(comp_ctx->builder) @@ -93,6 +105,11 @@ format_block_name(char *name, uint32 name_size, uint32 block_index, goto fail; \ } \ SET_BUILDER_POS(block->llvm_end_block); \ + LLVMValueRef first_instr = \ + get_first_non_phi(block->llvm_end_block); \ + if (first_instr) { \ + LLVMPositionBuilderBefore(comp_ctx->builder, first_instr); \ + } \ for (_i = 0; _i < block->result_count; _i++) { \ if (!(block->result_phis[_i] = LLVMBuildPhi( \ comp_ctx->builder, \ @@ -158,6 +175,18 @@ get_target_block(AOTFuncContext *func_ctx, uint32 br_depth) return block; } +LLVMValueRef +get_first_non_phi(LLVMBasicBlockRef block) +{ + LLVMValueRef instr = LLVMGetFirstInstruction(block); + + while (instr && LLVMIsAPHINode(instr)) { + instr = LLVMGetNextInstruction(instr); + } + + return instr; +} + static void clear_frame_locals(AOTCompFrame *aot_frame) { @@ -883,7 +912,7 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build LOAD failed"); return false; } - /* Set terminate_flags memory accecc to volatile, so that the value + /* Set terminate_flags memory access to volatile, so that the value will always be loaded from memory rather than register */ LLVMSetVolatile(terminate_flags, true); @@ -1361,6 +1390,13 @@ aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, (*p_frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code); #endif + if (comp_ctx->aux_stack_frame_type + && comp_ctx->call_stack_features.frame_per_function + && !aot_free_frame_per_function_frame_for_aot_func(comp_ctx, + func_ctx)) { + return false; + } + if (block_func->result_count) { /* Store extra result values to function parameters */ for (i = 0; i < block_func->result_count - 1; i++) { diff --git a/core/iwasm/compilation/aot_emit_exception.c b/core/iwasm/compilation/aot_emit_exception.c index d3dcf719d..1527e83e5 100644 --- a/core/iwasm/compilation/aot_emit_exception.c +++ b/core/iwasm/compilation/aot_emit_exception.c @@ -4,49 +4,10 @@ */ #include "aot_emit_exception.h" +#include "aot_compiler.h" #include "../interpreter/wasm_runtime.h" #include "../aot/aot_runtime.h" -static bool -commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - LLVMValueRef exce_ip, bool is_64bit) -{ - LLVMValueRef cur_frame = func_ctx->cur_frame; - LLVMValueRef value_offset, value_addr, value_ptr; - uint32 offset_ip; - - if (!comp_ctx->is_jit_mode) - offset_ip = comp_ctx->pointer_size * 4; - else - offset_ip = offsetof(WASMInterpFrame, ip); - - if (!(value_offset = I32_CONST(offset_ip))) { - aot_set_last_error("llvm build const failed"); - return false; - } - - if (!(value_addr = - LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame, - &value_offset, 1, "ip_addr"))) { - aot_set_last_error("llvm build in bounds gep failed"); - return false; - } - - if (!(value_ptr = LLVMBuildBitCast( - comp_ctx->builder, value_addr, - is_64bit ? INT64_PTR_TYPE : INT32_PTR_TYPE, "ip_ptr"))) { - aot_set_last_error("llvm build bit cast failed"); - return false; - } - - if (!LLVMBuildStore(comp_ctx->builder, exce_ip, value_ptr)) { - aot_set_last_error("llvm build store failed"); - return false; - } - - return true; -} - bool aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, int32 exception_id, bool is_cond_br, LLVMValueRef cond_br_if, @@ -80,7 +41,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } - if (comp_ctx->aot_frame) { + if (comp_ctx->aot_frame && comp_ctx->call_stack_features.trap_ip) { /* Create exception ip phi */ if (!(func_ctx->exception_ip_phi = LLVMBuildPhi( comp_ctx->builder, is_64bit ? I64_TYPE : I32_TYPE, @@ -90,8 +51,8 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* Commit ip to current frame */ - if (!commit_ip(comp_ctx, func_ctx, func_ctx->exception_ip_phi, - is_64bit)) { + if (!aot_gen_commit_ip(comp_ctx, func_ctx, + func_ctx->exception_ip_phi, is_64bit)) { return false; } } @@ -173,7 +134,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Add phi incoming value to got_exception block */ LLVMAddIncoming(func_ctx->exception_id_phi, &exce_id, &block_curr, 1); - if (comp_ctx->aot_frame) { + if (comp_ctx->aot_frame && comp_ctx->call_stack_features.trap_ip) { const uint8 *ip = comp_ctx->aot_frame->frame_ip; LLVMValueRef exce_ip = NULL; diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 8f6e3e456..49b1ac1cb 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -7,6 +7,7 @@ #include "aot_emit_exception.h" #include "aot_emit_control.h" #include "aot_emit_table.h" +#include "aot_stack_frame_comp.h" #include "../aot/aot_runtime.h" #if WASM_ENABLE_GC != 0 #include "aot_emit_gc.h" @@ -682,24 +683,29 @@ alloc_frame_for_aot_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, new_frame = wasm_stack_top; - if (!(check_wasm_stack_succ = LLVMAppendBasicBlockInContext( - comp_ctx->context, func_ctx->func, "check_wasm_stack_succ"))) { - aot_set_last_error("llvm add basic block failed."); - return false; - } + if (comp_ctx->call_stack_features.bounds_checks) { + if (!(check_wasm_stack_succ = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, + "check_wasm_stack_succ"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } - LLVMMoveBasicBlockAfter(check_wasm_stack_succ, - LLVMGetInsertBlock(comp_ctx->builder)); + LLVMMoveBasicBlockAfter(check_wasm_stack_succ, + LLVMGetInsertBlock(comp_ctx->builder)); - if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, wasm_stack_top_max, - wasm_stack_top_bound, "cmp"))) { - aot_set_last_error("llvm build icmp failed"); - return false; - } + if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, + wasm_stack_top_max, wasm_stack_top_bound, + "cmp"))) { + aot_set_last_error("llvm build icmp failed"); + return false; + } - if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_OPERAND_STACK_OVERFLOW, - true, cmp, check_wasm_stack_succ))) { - return false; + if (!(aot_emit_exception(comp_ctx, func_ctx, + EXCE_OPERAND_STACK_OVERFLOW, true, cmp, + check_wasm_stack_succ))) { + return false; + } } #if WASM_ENABLE_GC != 0 @@ -879,25 +885,28 @@ alloc_frame_for_aot_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (!comp_ctx->is_jit_mode) { - /* aot mode: new_frame->func_idx = func_idx */ - func_idx_val = comp_ctx->pointer_size == sizeof(uint64) - ? I64_CONST(func_idx) - : I32_CONST(func_idx); - offset = I32_CONST(comp_ctx->pointer_size); - CHECK_LLVM_CONST(func_idx_val); - CHECK_LLVM_CONST(offset); - if (!(func_idx_ptr = - LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, new_frame, - &offset, 1, "func_idx_addr")) - || !(func_idx_ptr = - LLVMBuildBitCast(comp_ctx->builder, func_idx_ptr, - INTPTR_T_PTR_TYPE, "func_idx_ptr"))) { - aot_set_last_error("llvm get func_idx_ptr failed"); - return false; - } - if (!LLVMBuildStore(comp_ctx->builder, func_idx_val, func_idx_ptr)) { - aot_set_last_error("llvm build store failed"); - return false; + if (comp_ctx->call_stack_features.func_idx) { + /* aot mode: new_frame->func_idx = func_idx */ + func_idx_val = comp_ctx->pointer_size == sizeof(uint64) + ? I64_CONST(func_idx) + : I32_CONST(func_idx); + offset = I32_CONST(comp_ctx->pointer_size); + CHECK_LLVM_CONST(func_idx_val); + CHECK_LLVM_CONST(offset); + if (!(func_idx_ptr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, INT8_TYPE, new_frame, &offset, 1, + "func_idx_addr")) + || !(func_idx_ptr = + LLVMBuildBitCast(comp_ctx->builder, func_idx_ptr, + INTPTR_T_PTR_TYPE, "func_idx_ptr"))) { + aot_set_last_error("llvm get func_idx_ptr failed"); + return false; + } + if (!LLVMBuildStore(comp_ctx->builder, func_idx_val, + func_idx_ptr)) { + aot_set_last_error("llvm build store failed"); + return false; + } } } else { @@ -1285,6 +1294,10 @@ commit_params_to_frame_of_import_func(AOTCompContext *comp_ctx, { uint32 i, n; + if (!comp_ctx->call_stack_features.values) { + return true; + } + for (i = 0, n = 0; i < func_type->param_count; i++, n++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: @@ -1394,6 +1407,9 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef *param_values = NULL, value_ret = NULL, func; LLVMValueRef import_func_idx, res; LLVMValueRef ext_ret, ext_ret_ptr, ext_ret_idx; +#if WASM_ENABLE_AOT_STACK_FRAME != 0 + LLVMValueRef func_idx_ref; +#endif int32 i, j = 0, param_count, result_count, ext_ret_count; uint64 total_size; uint8 wasm_ret_type; @@ -1438,12 +1454,28 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } - if (comp_ctx->enable_aux_stack_frame) { #if WASM_ENABLE_AOT_STACK_FRAME != 0 - if (!alloc_frame_for_aot_func(comp_ctx, func_ctx, func_idx)) - return false; -#endif + if (comp_ctx->aux_stack_frame_type) { + if (func_idx < import_func_count + && comp_ctx->call_stack_features.frame_per_function) { + INT_CONST(func_idx_ref, func_idx, I32_TYPE, true); + if (!aot_alloc_frame_per_function_frame_for_aot_func( + comp_ctx, func_ctx, func_idx_ref)) { + return false; + } + } + else if (!comp_ctx->call_stack_features.frame_per_function) { + if (comp_ctx->aux_stack_frame_type + != AOT_STACK_FRAME_TYPE_STANDARD) { + aot_set_last_error("unsupported mode"); + return false; + } + if (!alloc_frame_for_aot_func(comp_ctx, func_ctx, func_idx)) { + return false; + } + } } +#endif /* Get param cell number */ param_cell_num = func_type->param_cell_num; @@ -1513,7 +1545,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (func_idx < import_func_count) { - if (comp_ctx->enable_aux_stack_frame + if (comp_ctx->aux_stack_frame_type == AOT_STACK_FRAME_TYPE_STANDARD && !commit_params_to_frame_of_import_func( comp_ctx, func_ctx, func_type, param_values + 1)) { goto fail; @@ -1804,12 +1836,26 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - if (comp_ctx->enable_aux_stack_frame) { #if WASM_ENABLE_AOT_STACK_FRAME != 0 - if (!free_frame_for_aot_func(comp_ctx, func_ctx)) - goto fail; -#endif + if (comp_ctx->aux_stack_frame_type) { + if (func_idx < import_func_count + && comp_ctx->call_stack_features.frame_per_function) { + if (!aot_free_frame_per_function_frame_for_aot_func(comp_ctx, + func_ctx)) { + goto fail; + } + } + else if (!comp_ctx->call_stack_features.frame_per_function) { + if (comp_ctx->aux_stack_frame_type + != AOT_STACK_FRAME_TYPE_STANDARD) { + aot_set_last_error("unsupported mode"); + } + if (!free_frame_for_aot_func(comp_ctx, func_ctx)) { + goto fail; + } + } } +#endif /* Insert suspend check point */ if (comp_ctx->enable_thread_mgr) { @@ -2043,6 +2089,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef ext_ret_offset, ext_ret_ptr, ext_ret, res; LLVMValueRef *param_values = NULL, *value_rets = NULL; LLVMValueRef *result_phis = NULL, value_ret, import_func_count; +#if WASM_ENABLE_MEMORY64 != 0 + LLVMValueRef u32_max, u32_cmp_result = NULL; +#endif LLVMTypeRef *param_types = NULL, ret_type; LLVMTypeRef llvm_func_type, llvm_func_ptr_type; LLVMTypeRef ext_ret_ptr_type; @@ -2107,7 +2156,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, func_param_count = func_type->param_count; func_result_count = func_type->result_count; - POP_I32(elem_idx); + POP_TBL_ELEM_IDX(elem_idx); /* get the cur size of the table instance */ if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx) @@ -2136,6 +2185,27 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } +#if WASM_ENABLE_MEMORY64 != 0 + /* Check if elem index >= UINT32_MAX */ + if (IS_TABLE64(tbl_idx)) { + if (!(u32_max = I64_CONST(UINT32_MAX))) { + aot_set_last_error("llvm build const failed"); + goto fail; + } + if (!(u32_cmp_result = + LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx, + u32_max, "cmp_elem_idx_u32_max"))) { + aot_set_last_error("llvm build icmp failed."); + goto fail; + } + if (!(elem_idx = LLVMBuildTrunc(comp_ctx->builder, elem_idx, I32_TYPE, + "elem_idx_i32"))) { + aot_set_last_error("llvm build trunc failed."); + goto fail; + } + } +#endif + /* Check if (uint32)elem index >= table size */ if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx, table_size_const, "cmp_elem_idx"))) { @@ -2143,7 +2213,19 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - /* Throw exception if elem index >= table size */ +#if WASM_ENABLE_MEMORY64 != 0 + if (IS_TABLE64(tbl_idx)) { + if (!(cmp_elem_idx = + LLVMBuildOr(comp_ctx->builder, cmp_elem_idx, u32_cmp_result, + "larger_than_u32_max_or_cur_size"))) { + aot_set_last_error("llvm build or failed."); + goto fail; + } + } +#endif + + /* Throw exception if elem index >= table size or elem index >= UINT32_MAX + */ if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext( comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) { aot_set_last_error("llvm add basic block failed."); @@ -2430,7 +2512,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - if (comp_ctx->enable_aux_stack_frame) { + if (comp_ctx->aux_stack_frame_type + && !comp_ctx->call_stack_features.frame_per_function) { #if WASM_ENABLE_AOT_STACK_FRAME != 0 /* TODO: use current frame instead of allocating new frame for WASM_OP_RETURN_CALL_INDIRECT */ @@ -2499,7 +2582,13 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Translate call import block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_import); - if (comp_ctx->enable_aux_stack_frame + if (comp_ctx->aot_frame && comp_ctx->call_stack_features.frame_per_function + && !aot_alloc_frame_per_function_frame_for_aot_func(comp_ctx, func_ctx, + func_idx)) { + goto fail; + } + + if (comp_ctx->aux_stack_frame_type == AOT_STACK_FRAME_TYPE_STANDARD && !commit_params_to_frame_of_import_func(comp_ctx, func_ctx, func_type, param_values + 1)) { goto fail; @@ -2536,6 +2625,12 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, && !check_call_return(comp_ctx, func_ctx, res)) goto fail; + if (comp_ctx->aot_frame && comp_ctx->call_stack_features.frame_per_function + && !aot_free_frame_per_function_frame_for_aot_func(comp_ctx, + func_ctx)) { + goto fail; + } + block_curr = LLVMGetInsertBlock(comp_ctx->builder); for (i = 0; i < func_result_count; i++) { LLVMAddIncoming(result_phis[i], &value_rets[i], &block_curr, 1); @@ -2620,7 +2715,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, PUSH(result_phis[i], func_type->types[func_param_count + i]); } - if (comp_ctx->enable_aux_stack_frame) { + if (comp_ctx->aux_stack_frame_type + && !comp_ctx->call_stack_features.frame_per_function) { #if WASM_ENABLE_AOT_STACK_FRAME != 0 if (!free_frame_for_aot_func(comp_ctx, func_ctx)) goto fail; @@ -2927,7 +3023,8 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - if (comp_ctx->enable_aux_stack_frame) { + if (comp_ctx->aux_stack_frame_type + && !comp_ctx->call_stack_features.frame_per_function) { #if WASM_ENABLE_AOT_STACK_FRAME != 0 /* TODO: use current frame instead of allocating new frame for WASM_OP_RETURN_CALL_REF */ @@ -2996,7 +3093,7 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Translate call import block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_import); - if (comp_ctx->enable_aux_stack_frame + if (comp_ctx->aux_stack_frame_type == AOT_STACK_FRAME_TYPE_STANDARD && !commit_params_to_frame_of_import_func(comp_ctx, func_ctx, func_type, param_values + 1)) { goto fail; @@ -3124,7 +3221,8 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, PUSH(result_phis[i], func_type->types[func_param_count + i]); } - if (comp_ctx->enable_aux_stack_frame) { + if (comp_ctx->aux_stack_frame_type + && !comp_ctx->call_stack_features.frame_per_function) { #if WASM_ENABLE_AOT_STACK_FRAME != 0 if (!free_frame_for_aot_func(comp_ctx, func_ctx)) goto fail; diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 806150ff1..869a1dbb2 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -118,10 +118,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef offset_const = MEMORY64_COND_VALUE(I64_CONST(offset), I32_CONST(offset)); - LLVMValueRef addr, maddr, offset1, cmp1, cmp2, cmp; + LLVMValueRef addr, maddr, maddr_phi = NULL, offset1, cmp1, cmp2, cmp; LLVMValueRef mem_base_addr, mem_check_bound; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); - LLVMBasicBlockRef check_succ; + LLVMBasicBlockRef check_succ, block_maddr_phi = NULL; AOTValue *aot_value_top; uint32 local_idx_of_aot_value = 0; uint64 const_value; @@ -131,6 +131,11 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool is_shared_memory = comp_ctx->comp_data->memories[0].flags & SHARED_MEMORY_FLAG; #endif +#if WASM_ENABLE_MEMORY64 == 0 + bool is_memory64 = false; +#else + bool is_memory64 = IS_MEMORY64; +#endif is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false; @@ -268,8 +273,137 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* offset1 = offset + addr; */ + /* TODO: check whether integer overflow occurs when memory is 64-bit + and boundary check is enabled */ BUILD_OP(Add, offset_const, addr, offset1, "offset1"); + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem; + LLVMValueRef is_in_shared_heap, shared_heap_check_bound = NULL; + + /* Add basic blocks */ + ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap"); + ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem"); + ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi"); + + LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr); + LLVMMoveBasicBlockAfter(app_addr_in_linear_mem, + app_addr_in_shared_heap); + LLVMMoveBasicBlockAfter(block_maddr_phi, app_addr_in_linear_mem); + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); + if (!(maddr_phi = + LLVMBuildPhi(comp_ctx->builder, + enable_segue ? INT8_PTR_TYPE_GS : INT8_PTR_TYPE, + "maddr_phi"))) { + aot_set_last_error("llvm build phi failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); + + if (!is_target_64bit) { + /* Check whether interger overflow occurs in addr + offset */ + LLVMBasicBlockRef check_integer_overflow_end; + ADD_BASIC_BLOCK(check_integer_overflow_end, + "check_integer_overflow_end"); + LLVMMoveBasicBlockAfter(check_integer_overflow_end, block_curr); + + BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); + if (!aot_emit_exception(comp_ctx, func_ctx, + EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, + cmp1, check_integer_overflow_end)) { + goto fail; + } + SET_BUILD_POS(check_integer_overflow_end); + } + + shared_heap_check_bound = + is_memory64 ? I64_CONST(UINT64_MAX - bytes + 1) + : (comp_ctx->pointer_size == sizeof(uint64) + ? I64_CONST(UINT32_MAX - bytes + 1) + : I32_CONST(UINT32_MAX - bytes + 1)); + CHECK_LLVM_CONST(shared_heap_check_bound); + + /* Check whether the bytes to access are in shared heap */ + if (!comp_ctx->enable_bound_check) { + /* Use IntUGT but not IntUGE to compare, since (1) in the ems + memory allocator, the hmu node includes hmu header and hmu + memory, only the latter is returned to the caller as the + allocated memory, the hmu header isn't returned so the + first byte of the shared heap won't be accesed, (2) using + IntUGT gets better performance than IntUGE in some cases */ + BUILD_ICMP(LLVMIntUGT, offset1, func_ctx->shared_heap_start_off, + is_in_shared_heap, "is_in_shared_heap"); + /* We don't check the shared heap's upper boundary if boundary + check isn't enabled, the runtime may also use the guard pages + of shared heap to check the boundary if hardware boundary + check feature is enabled. */ + } + else { + /* Use IntUGT but not IntUGE to compare, same as above */ + BUILD_ICMP(LLVMIntUGT, offset1, func_ctx->shared_heap_start_off, + cmp1, "cmp1"); + /* Check the shared heap's upper boundary if boundary check is + enabled */ + BUILD_ICMP(LLVMIntULE, offset1, shared_heap_check_bound, cmp2, + "cmp2"); + BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap"); + } + + if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap, + app_addr_in_shared_heap, app_addr_in_linear_mem)) { + aot_set_last_error("llvm build cond br failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap); + + /* Get native address inside shared heap */ + if (!(maddr = + LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->shared_heap_base_addr_adj, + &offset1, 1, "maddr_shared_heap"))) { + aot_set_last_error("llvm build inbounds gep failed"); + goto fail; + } + + if (enable_segue) { + LLVMValueRef mem_base_addr_u64, maddr_u64, offset_to_mem_base; + + if (!(maddr_u64 = LLVMBuildPtrToInt(comp_ctx->builder, maddr, + I64_TYPE, "maddr_u64")) + || !(mem_base_addr_u64 = + LLVMBuildPtrToInt(comp_ctx->builder, mem_base_addr, + I64_TYPE, "mem_base_addr_u64"))) { + aot_set_last_error("llvm build ptr to int failed"); + goto fail; + } + if (!(offset_to_mem_base = + LLVMBuildSub(comp_ctx->builder, maddr_u64, + mem_base_addr_u64, "offset_to_mem_base"))) { + aot_set_last_error("llvm build sub failed"); + goto fail; + } + if (!(maddr = LLVMBuildIntToPtr( + comp_ctx->builder, offset_to_mem_base, INT8_PTR_TYPE_GS, + "maddr_shared_heap_segue"))) { + aot_set_last_error("llvm build int to ptr failed."); + goto fail; + } + } + + LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1); + + if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { + aot_set_last_error("llvm build br failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem); + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + } + if (comp_ctx->enable_bound_check && !(is_local_of_aot_value && aot_checked_addr_list_find(func_ctx, local_idx_of_aot_value, @@ -305,10 +439,16 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp"); } else { - /* Check integer overflow */ - BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); - BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2"); - BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + /* Check integer overflow has been checked above */ + BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp"); + } + else { + /* Check integer overflow */ + BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); + BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2"); + BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); + } } /* Add basic blocks */ @@ -354,7 +494,19 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } } - return maddr; + + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1); + if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { + aot_set_last_error("llvm build br failed"); + goto fail; + } + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); + return maddr_phi; + } + else + return maddr; fail: return NULL; } @@ -985,10 +1137,15 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef offset, LLVMValueRef bytes) { LLVMValueRef maddr, max_addr, cmp; - LLVMValueRef mem_base_addr; + LLVMValueRef mem_base_addr, maddr_phi = NULL; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); - LLVMBasicBlockRef check_succ; + LLVMBasicBlockRef check_succ, block_maddr_phi = NULL; LLVMValueRef mem_size; +#if WASM_ENABLE_MEMORY64 == 0 + bool is_memory64 = false; +#else + bool is_memory64 = IS_MEMORY64; +#endif /* Get memory base address and memory data size */ #if WASM_ENABLE_SHARED_MEMORY != 0 @@ -1053,9 +1210,96 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, offset = LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset"); bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len"); + if (!offset || !bytes) { + aot_set_last_error("llvm build zext failed."); + goto fail; + } + /* TODO: check whether integer overflow occurs when memory is 64-bit + and boundary check is enabled */ BUILD_OP(Add, offset, bytes, max_addr, "max_addr"); + + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem; + LLVMValueRef shared_heap_start_off, shared_heap_check_bound; + LLVMValueRef max_offset, cmp1, cmp2, is_in_shared_heap; + + /* Add basic blocks */ + ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap"); + ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem"); + ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi"); + + LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr); + LLVMMoveBasicBlockAfter(app_addr_in_linear_mem, + app_addr_in_shared_heap); + LLVMMoveBasicBlockAfter(block_maddr_phi, check_succ); + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); + if (!(maddr_phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE, + "maddr_phi"))) { + aot_set_last_error("llvm build phi failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); + + shared_heap_start_off = func_ctx->shared_heap_start_off; + if (comp_ctx->pointer_size == sizeof(uint32)) { + if (!(shared_heap_start_off = + LLVMBuildZExt(comp_ctx->builder, shared_heap_start_off, + I64_TYPE, "shared_heap_start_off_u64"))) { + aot_set_last_error("llvm build zext failed"); + goto fail; + } + } + shared_heap_check_bound = + is_memory64 ? I64_CONST(UINT64_MAX) : I64_CONST(UINT32_MAX); + CHECK_LLVM_CONST(shared_heap_check_bound); + + /* Check whether the bytes to access are in shared heap */ + if (!comp_ctx->enable_bound_check) { + /* Use IntUGT but not IntUGE to compare, same as the check + in aot_check_memory_overflow */ + BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off, + is_in_shared_heap, "is_in_shared_heap"); + } + else { + BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off, + cmp1, "cmp1"); + BUILD_OP(Add, max_addr, I64_NEG_ONE, max_offset, "max_offset"); + BUILD_ICMP(LLVMIntULE, max_offset, shared_heap_check_bound, cmp2, + "cmp2"); + BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap"); + } + + if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap, + app_addr_in_shared_heap, app_addr_in_linear_mem)) { + aot_set_last_error("llvm build cond br failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap); + + /* Get native address inside shared heap */ + if (!(maddr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->shared_heap_base_addr_adj, + &offset, 1, "maddr_shared_heap"))) { + aot_set_last_error("llvm build inbounds gep failed"); + goto fail; + } + LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1); + + if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { + aot_set_last_error("llvm build br failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem); + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + } + BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp, "cmp_max_mem_addr"); + if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp, check_succ)) { @@ -1068,11 +1312,23 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build add failed."); goto fail; } - return maddr; + + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1); + if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { + aot_set_last_error("llvm build br failed"); + goto fail; + } + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); + return maddr_phi; + } + else + return maddr; fail: return NULL; } -#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 or WASM_ENABLE_STRINGREF != 0 */ +#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_STRINGREF != 0 */ #if WASM_ENABLE_BULK_MEMORY != 0 bool diff --git a/core/iwasm/compilation/aot_emit_table.c b/core/iwasm/compilation/aot_emit_table.c index f968bacdd..e8dae410b 100644 --- a/core/iwasm/compilation/aot_emit_table.c +++ b/core/iwasm/compilation/aot_emit_table.c @@ -10,6 +10,78 @@ #include "aot_emit_gc.h" #endif +#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 +#if WASM_ENABLE_MEMORY64 != 0 +static bool +zero_extend_u64(AOTCompContext *comp_ctx, LLVMValueRef *value, const char *name) +{ + if (comp_ctx->pointer_size == sizeof(uint64)) { + /* zero extend to uint64 if the target is 64-bit */ + *value = LLVMBuildZExt(comp_ctx->builder, *value, I64_TYPE, name); + if (!*value) { + aot_set_last_error("llvm build zero extend failed."); + return false; + } + } + return true; +} +#endif + +/* check whether a table64 elem idx is greater than UINT32_MAX, if so, throw + * exception, otherwise trunc it to uint32 */ +static bool +check_tbl_elem_idx_and_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef *elem_idx, uint32 tbl_idx) +{ +#if WASM_ENABLE_MEMORY64 != 0 + LLVMValueRef u32_max, u32_cmp_result; + LLVMBasicBlockRef check_elem_idx_succ; + + if (!IS_TABLE64(tbl_idx)) { + return true; + } + + /* Check if elem index >= UINT32_MAX */ + if (!(u32_max = I64_CONST(UINT32_MAX))) { + aot_set_last_error("llvm build const failed"); + goto fail; + } + if (!(u32_cmp_result = + LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, *elem_idx, u32_max, + "cmp_elem_idx_u32_max"))) { + aot_set_last_error("llvm build icmp failed."); + goto fail; + } + if (!(*elem_idx = LLVMBuildTrunc(comp_ctx->builder, *elem_idx, I32_TYPE, + "elem_idx_i32"))) { + aot_set_last_error("llvm build trunc failed."); + goto fail; + } + + /* Throw exception if elem index >= UINT32_MAX*/ + if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) { + aot_set_last_error("llvm add basic block failed."); + goto fail; + } + + LLVMMoveBasicBlockAfter(check_elem_idx_succ, + LLVMGetInsertBlock(comp_ctx->builder)); + + if (!(aot_emit_exception(comp_ctx, func_ctx, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, true, + u32_cmp_result, check_elem_idx_succ))) + goto fail; + + return true; +fail: + return false; +#else + return true; +#endif +} +#endif /* WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC !=0 */ + uint64 get_tbl_inst_offset(const AOTCompContext *comp_ctx, const AOTFuncContext *func_ctx, uint32 tbl_idx) @@ -158,6 +230,10 @@ aot_check_table_access(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &elem_idx, tbl_idx)) { + goto fail; + } + /* Check if (uint32)elem index >= table size */ if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx, tbl_sz, "cmp_elem_idx"))) { @@ -192,7 +268,7 @@ aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef elem_idx, offset, func_idx; LLVMValueRef table_elem_base, table_elem_addr, table_elem; - POP_I32(elem_idx); + POP_TBL_ELEM_IDX(elem_idx); if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) { goto fail; @@ -289,7 +365,7 @@ aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - POP_I32(elem_idx); + POP_TBL_ELEM_IDX(elem_idx); if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) { goto fail; @@ -388,7 +464,11 @@ aot_compile_op_table_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* s */ POP_I32(param_values[4]); /* d */ - POP_I32(param_values[5]); + POP_TBL_ELEM_IDX(param_values[5]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[5], + tbl_idx)) { + goto fail; + } /* "" means return void */ if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6, @@ -408,6 +488,7 @@ aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type; LLVMValueRef func, param_values[6], value; + uint32 tbl_idx; param_types[0] = INT8_PTR_TYPE; param_types[1] = I32_TYPE; @@ -434,12 +515,34 @@ aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } + /* In table64, the length should be i32 type if any one of src/dst table + * is i32 type, set the table index to the lesser-or-equal table when + * popping length n */ + if (!(comp_ctx->comp_data->tables[src_tbl_idx].table_type.flags + & TABLE64_FLAG)) + tbl_idx = src_tbl_idx; + else + tbl_idx = dst_tbl_idx; /* n */ - POP_I32(param_values[3]); + POP_TBL_ELEM_LEN(param_values[3]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[3], + tbl_idx)) { + goto fail; + } /* s */ - POP_I32(param_values[4]); + tbl_idx = src_tbl_idx; + POP_TBL_ELEM_IDX(param_values[4]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[4], + tbl_idx)) { + goto fail; + } /* d */ - POP_I32(param_values[5]); + tbl_idx = dst_tbl_idx; + POP_TBL_ELEM_IDX(param_values[5]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[5], + tbl_idx)) { + goto fail; + } /* "" means return void */ if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6, @@ -484,7 +587,14 @@ aot_compile_op_table_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - PUSH_I32(tbl_sz); +#if WASM_ENABLE_MEMORY64 != 0 + if (IS_TABLE64(tbl_idx)) { + if (!zero_extend_u64(comp_ctx, &tbl_sz, "length64")) { + goto fail; + } + } +#endif + PUSH_TBL_ELEM_IDX(tbl_sz); return true; fail: @@ -517,7 +627,11 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* n */ - POP_I32(param_values[2]); + POP_TBL_ELEM_LEN(param_values[2]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[2], + tbl_idx)) { + goto fail; + } /* v */ if (comp_ctx->enable_gc) { @@ -545,7 +659,14 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - PUSH_I32(ret); +#if WASM_ENABLE_MEMORY64 != 0 + if (IS_TABLE64(tbl_idx)) { + if (!zero_extend_u64(comp_ctx, &ret, "table_size64")) { + goto fail; + } + } +#endif + PUSH_TBL_ELEM_LEN(ret); return true; fail: @@ -579,7 +700,11 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* n */ - POP_I32(param_values[2]); + POP_TBL_ELEM_LEN(param_values[2]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[2], + tbl_idx)) { + goto fail; + } /* v */ if (comp_ctx->enable_gc) { @@ -601,7 +726,11 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } /* i */ - POP_I32(param_values[4]); + POP_TBL_ELEM_IDX(param_values[4]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[4], + tbl_idx)) { + goto fail; + } /* "" means return void */ if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 5, @@ -615,4 +744,4 @@ fail: return false; } -#endif /* WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC !=0 */ +#endif /* WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC !=0 */ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index d738cfc0e..fb1c4308b 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1518,6 +1518,75 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } +static bool +create_shared_heap_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef offset, base_addr_p, start_off_p, cmp; + uint32 offset_u32; + + /* Load aot_inst->e->shared_heap_base_addr_adj */ + offset_u32 = get_module_inst_extra_offset(comp_ctx); +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0 + if (comp_ctx->is_jit_mode) + offset_u32 += + offsetof(WASMModuleInstanceExtra, shared_heap_base_addr_adj); + else +#endif + offset_u32 += + offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj); + offset = I32_CONST(offset_u32); + CHECK_LLVM_CONST(offset); + + if (!(base_addr_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->aot_inst, &offset, 1, + "shared_heap_base_addr_adj_p"))) { + aot_set_last_error("llvm build inbounds gep failed"); + return false; + } + if (!(func_ctx->shared_heap_base_addr_adj = + LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE, base_addr_p, + "shared_heap_base_addr_adj"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + /* Load aot_inst->e->shared_heap_start_off */ + offset_u32 = get_module_inst_extra_offset(comp_ctx); +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0 + if (comp_ctx->is_jit_mode) + offset_u32 += offsetof(WASMModuleInstanceExtra, shared_heap_start_off); + else +#endif + offset_u32 += offsetof(AOTModuleInstanceExtra, shared_heap_start_off); + offset = I32_CONST(offset_u32); + CHECK_LLVM_CONST(offset); + + if (!(start_off_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->aot_inst, &offset, 1, + "shared_heap_start_off_p"))) { + aot_set_last_error("llvm build inbounds gep failed"); + return false; + } + if (!(func_ctx->shared_heap_start_off = LLVMBuildLoad2( + comp_ctx->builder, + comp_ctx->pointer_size == sizeof(uint64) ? I64_TYPE : I32_TYPE, + start_off_p, "shared_heap_start_off"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + if (!(cmp = LLVMBuildIsNotNull(comp_ctx->builder, + func_ctx->shared_heap_base_addr_adj, + "has_shared_heap"))) { + aot_set_last_error("llvm build is not null failed"); + return false; + } + + return true; +fail: + return false; +} + static bool create_cur_exception(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { @@ -1771,7 +1840,7 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx, goto fail; } - if (comp_ctx->enable_aux_stack_frame + if (comp_ctx->aux_stack_frame_type && !create_aux_stack_frame(comp_ctx, func_ctx)) { goto fail; } @@ -1808,6 +1877,12 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx, goto fail; } + /* Load shared heap, shared heap start off mem32 or mem64 */ + if (comp_ctx->enable_shared_heap + && !create_shared_heap_info(comp_ctx, func_ctx)) { + goto fail; + } + return func_ctx; fail: @@ -2577,8 +2652,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) if (option->enable_ref_types) comp_ctx->enable_ref_types = true; - if (option->enable_aux_stack_frame) - comp_ctx->enable_aux_stack_frame = true; + comp_ctx->aux_stack_frame_type = option->aux_stack_frame_type; + comp_ctx->call_stack_features = option->call_stack_features; if (option->enable_perf_profiling) comp_ctx->enable_perf_profiling = true; @@ -2619,6 +2694,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) if (option->enable_gc) comp_ctx->enable_gc = true; + if (option->enable_shared_heap) + comp_ctx->enable_shared_heap = true; + comp_ctx->opt_level = option->opt_level; comp_ctx->size_level = option->size_level; @@ -2790,6 +2868,15 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) bh_assert(vendor_sys); bh_memcpy_s(default_arch, sizeof(default_arch), default_triple, (uint32)(vendor_sys - default_triple)); + /** + * On Mac M[1-9]+ LLVM will report arm64 as the + * architecture, for the purposes of wamr this is the + * same as aarch64v8 so we'll normalize it here. + */ + if (!strcmp(default_arch, "arm64")) { + bh_strcpy_s(default_arch, sizeof(default_arch), + "aarch64v8"); + } arch1 = default_arch; LLVMDisposeMessage(default_triple); @@ -2960,12 +3047,12 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) sizeof(comp_ctx->target_arch)); if (option->bounds_checks == 1 || option->bounds_checks == 0) { - /* Set by user */ + /* Set by the user */ comp_ctx->enable_bound_check = (option->bounds_checks == 1) ? true : false; } else { - /* Unset by user, use default value */ + /* Unset by the user, use the default value */ if (strstr(comp_ctx->target_arch, "64") && !option->is_sgx_platform) { comp_ctx->enable_bound_check = false; @@ -2975,17 +3062,17 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) } } - if (comp_ctx->enable_bound_check) { - /* Always enable stack boundary check if `bounds-checks` - is enabled */ - comp_ctx->enable_stack_bound_check = true; - } - else { - /* When `bounds-checks` is disabled, we set stack boundary - check status according to the input option */ + if (option->stack_bounds_checks == 1 + || option->stack_bounds_checks == 0) { + /* Set by the user */ comp_ctx->enable_stack_bound_check = (option->stack_bounds_checks == 1) ? true : false; } + else { + /* Unset by the user, use the default value, it will be the same + * value as the bound check */ + comp_ctx->enable_stack_bound_check = comp_ctx->enable_bound_check; + } if ((comp_ctx->enable_stack_bound_check || comp_ctx->enable_stack_estimation) diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 270e5ae45..0dce988bc 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -242,6 +242,9 @@ typedef struct AOTFuncContext { bool mem_space_unchanged; AOTCheckedAddrList checked_addr_list; + LLVMValueRef shared_heap_base_addr_adj; + LLVMValueRef shared_heap_start_off; + LLVMBasicBlockRef got_exception_block; LLVMBasicBlockRef func_return_block; LLVMValueRef exception_id_phi; @@ -410,7 +413,10 @@ typedef struct AOTCompContext { bool enable_aux_stack_check; /* Generate auxiliary stack frame */ - bool enable_aux_stack_frame; + AOTStackFrameType aux_stack_frame_type; + + /* Auxiliary call stack features */ + AOTCallStackFeatures call_stack_features; /* Function performance profiling */ bool enable_perf_profiling; @@ -464,6 +470,8 @@ typedef struct AOTCompContext { /* Enable GC */ bool enable_gc; + bool enable_shared_heap; + uint32 opt_level; uint32 size_level; diff --git a/core/iwasm/compilation/aot_stack_frame.h b/core/iwasm/compilation/aot_stack_frame.h new file mode 100644 index 000000000..6155ee6e9 --- /dev/null +++ b/core/iwasm/compilation/aot_stack_frame.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _AOT_STACK_FRAME_H_ +#define _AOT_STACK_FRAME_H_ + +#include "platform_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + /* The non-imported function index of current function */ + uint32 func_index; + + /* Instruction pointer: offset to the bytecode array */ + uint32 ip_offset; +} AOTTinyFrame; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/iwasm/compilation/aot_stack_frame_comp.c b/core/iwasm/compilation/aot_stack_frame_comp.c new file mode 100644 index 000000000..fb540e643 --- /dev/null +++ b/core/iwasm/compilation/aot_stack_frame_comp.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2024 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include "aot_stack_frame_comp.h" +#include "aot_emit_exception.h" + +#define ADD_IN_BOUNDS_GEP(variable, type, pointer, indices, num_indices) \ + do { \ + if (!(variable = \ + LLVMBuildInBoundsGEP2(comp_ctx->builder, type, pointer, \ + indices, num_indices, #variable))) { \ + aot_set_last_error("llvm build in bounds gep failed"); \ + return false; \ + } \ + } while (0) + +#define ADD_STORE(value, pointer) \ + do { \ + if (!LLVMBuildStore(comp_ctx->builder, value, pointer)) { \ + aot_set_last_error("llvm build store failed"); \ + return false; \ + } \ + } while (0) + +#define ADD_LOAD(value, type, pointer) \ + do { \ + if (!(value = \ + LLVMBuildLoad2(comp_ctx->builder, type, pointer, #value))) { \ + aot_set_last_error("llvm build load failed"); \ + return false; \ + } \ + } while (0) + +static bool +aot_alloc_tiny_frame_for_aot_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMValueRef func_index) +{ + LLVMValueRef wasm_stack_top_ptr = func_ctx->wasm_stack_top_ptr, + wasm_stack_top_bound = func_ctx->wasm_stack_top_bound, + wasm_stack_top, cmp; + LLVMBasicBlockRef check_wasm_stack_succ; + LLVMValueRef offset; + + ADD_LOAD(wasm_stack_top, INT8_PTR_TYPE, wasm_stack_top_ptr); + + if (comp_ctx->call_stack_features.bounds_checks) { + if (!(check_wasm_stack_succ = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, + "check_wasm_stack_succ"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } + + LLVMMoveBasicBlockAfter(check_wasm_stack_succ, + LLVMGetInsertBlock(comp_ctx->builder)); + + if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, wasm_stack_top, + wasm_stack_top_bound, "cmp"))) { + aot_set_last_error("llvm build icmp failed"); + return false; + } + + if (!(aot_emit_exception(comp_ctx, func_ctx, + EXCE_OPERAND_STACK_OVERFLOW, true, cmp, + check_wasm_stack_succ))) { + return false; + } + } + + /* Save the func_idx on the top of the stack */ + if (comp_ctx->call_stack_features.func_idx) { + ADD_STORE(func_index, wasm_stack_top); + } + + /* increment the stack pointer */ + INT_CONST(offset, sizeof(AOTTinyFrame), I32_TYPE, true); + ADD_IN_BOUNDS_GEP(wasm_stack_top, INT8_TYPE, wasm_stack_top, &offset, 1); + ADD_STORE(wasm_stack_top, wasm_stack_top_ptr); + + return true; +} + +static bool +aot_free_tiny_frame_for_aot_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + LLVMValueRef wasm_stack_top_ptr = func_ctx->wasm_stack_top_ptr, + wasm_stack_top; + LLVMValueRef offset; + + ADD_LOAD(wasm_stack_top, INT8_PTR_TYPE, wasm_stack_top_ptr); + + INT_CONST(offset, -sizeof(AOTTinyFrame), + comp_ctx->pointer_size == 8 ? I64_TYPE : I32_TYPE, true); + ADD_IN_BOUNDS_GEP(wasm_stack_top, INT8_TYPE, wasm_stack_top, &offset, 1); + ADD_STORE(wasm_stack_top, wasm_stack_top_ptr); + + return true; +} + +bool +aot_tiny_frame_gen_commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef ip_value) +{ + LLVMValueRef wasm_stack_top_ptr = func_ctx->wasm_stack_top_ptr, + wasm_stack_top; + LLVMValueRef offset, ip_addr; + + bh_assert(ip_value); + + ADD_LOAD(wasm_stack_top, INT8_PTR_TYPE, wasm_stack_top_ptr); + + INT_CONST(offset, -4, comp_ctx->pointer_size == 8 ? I64_TYPE : I32_TYPE, + true); + ADD_IN_BOUNDS_GEP(ip_addr, INT8_TYPE, wasm_stack_top, &offset, 1); + + ADD_STORE(ip_value, ip_addr); + + return true; +} + +bool +aot_alloc_frame_per_function_frame_for_aot_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMValueRef func_index) +{ + switch (comp_ctx->aux_stack_frame_type) { + case AOT_STACK_FRAME_TYPE_TINY: + return aot_alloc_tiny_frame_for_aot_func(comp_ctx, func_ctx, + func_index); + default: + aot_set_last_error("unsupported mode"); + return false; + } +} + +bool +aot_free_frame_per_function_frame_for_aot_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx) +{ + switch (comp_ctx->aux_stack_frame_type) { + case AOT_STACK_FRAME_TYPE_TINY: + return aot_free_tiny_frame_for_aot_func(comp_ctx, func_ctx); + default: + aot_set_last_error("unsupported mode"); + return false; + } +} diff --git a/core/iwasm/compilation/aot_stack_frame_comp.h b/core/iwasm/compilation/aot_stack_frame_comp.h new file mode 100644 index 000000000..7980b8c08 --- /dev/null +++ b/core/iwasm/compilation/aot_stack_frame_comp.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _AOT_STACK_FRAME_COMP_H_ +#define _AOT_STACK_FRAME_COMP_H_ + +#include "aot_stack_frame.h" +#include "aot_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +aot_alloc_frame_per_function_frame_for_aot_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMValueRef func_index); + +bool +aot_free_frame_per_function_frame_for_aot_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); + +bool +aot_tiny_frame_gen_commit_ip(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef ip_value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/iwasm/include/aot_comp_option.h b/core/iwasm/include/aot_comp_option.h index 617b68f97..a97275d24 100644 --- a/core/iwasm/include/aot_comp_option.h +++ b/core/iwasm/include/aot_comp_option.h @@ -6,6 +6,49 @@ #ifndef __AOT_COMP_OPTION_H__ #define __AOT_COMP_OPTION_H__ +#include + +typedef struct { + /* Enables or disables bounds checks for stack frames. When enabled, the AOT + * compiler generates code to check if the stack pointer is within the + * bounds of the current stack frame (and if not, traps). */ + bool bounds_checks; + + /* Enables or disables instruction pointer (IP) tracking. */ + bool ip; + + /* Enables or disables function index in the stack trace. Please note that + * function index can be recovered from the instruction pointer using + * ip2function.py script, so enabling this feature along with `ip` might + * often be redundant. + * This option will automatically be enabled for GC and Perf Profiling mode. + */ + bool func_idx; + + /* Enables or disables tracking instruction pointer of a trap. Only takes + * effect when `ip` is enabled. */ + bool trap_ip; + + /* Enables or disables parameters, locals and stack operands. */ + bool values; + + /* If enabled, stack frame is generated at the beginning of each + * function (frame-per-function mode). Otherwise, stack frame is + * generated before each call of a function (frame-per-call mode). */ + bool frame_per_function; +} AOTCallStackFeatures; + +void +aot_call_stack_features_init_default(AOTCallStackFeatures *features); + +typedef enum { + AOT_STACK_FRAME_OFF = 0, + /* Use a small stack frame data structure (AOTTinyFrame) */ + AOT_STACK_FRAME_TYPE_TINY, + /* Use a regular stack frame data structure (AOTFrame) */ + AOT_STACK_FRAME_TYPE_STANDARD, +} AOTStackFrameType; + typedef struct AOTCompOption { bool is_jit_mode; bool is_indirect_mode; @@ -21,7 +64,8 @@ typedef struct AOTCompOption { bool enable_ref_types; bool enable_gc; bool enable_aux_stack_check; - bool enable_aux_stack_frame; + AOTStackFrameType aux_stack_frame_type; + AOTCallStackFeatures call_stack_features; bool enable_perf_profiling; bool enable_memory_profiling; bool disable_llvm_intrinsics; @@ -29,6 +73,7 @@ typedef struct AOTCompOption { bool enable_llvm_pgo; bool enable_stack_estimation; bool quick_invoke_c_api_import; + bool enable_shared_heap; char *use_prof_file; uint32_t opt_level; uint32_t size_level; diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index 4994454bd..9fc460148 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -534,6 +534,10 @@ typedef struct LoadArgs { bool clone_wasm_binary; /* This option is only used by the AOT/wasm loader (see wasm_export.h) */ bool wasm_binary_freeable; + /* false by default, if true, don't resolve the symbols yet. The + wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols + call */ + bool no_resolve; /* TODO: more fields? */ } LoadArgs; #endif /* LOAD_ARGS_OPTION_DEFINED */ diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 569c4deaa..aa6cfaae7 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -120,6 +120,10 @@ typedef struct WASMModuleInstanceCommon *wasm_module_inst_t; typedef void WASMFunctionInstanceCommon; typedef WASMFunctionInstanceCommon *wasm_function_inst_t; +/* Memory instance */ +struct WASMMemoryInstance; +typedef struct WASMMemoryInstance *wasm_memory_inst_t; + /* WASM section */ typedef struct wasm_section_t { struct wasm_section_t *next; @@ -135,6 +139,9 @@ typedef struct wasm_section_t { struct WASMExecEnv; typedef struct WASMExecEnv *wasm_exec_env_t; +struct WASMSharedHeap; +typedef struct WASMSharedHeap *wasm_shared_heap_t; + /* Package Type */ typedef enum { Wasm_Module_Bytecode = 0, @@ -248,6 +255,11 @@ typedef struct LoadArgs { const strings), making it possible to free the wasm binary buffer after loading. */ bool wasm_binary_freeable; + + /* false by default, if true, don't resolve the symbols yet. The + wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols + call */ + bool no_resolve; /* TODO: more fields? */ } LoadArgs; #endif /* LOAD_ARGS_OPTION_DEFINED */ @@ -320,6 +332,10 @@ typedef enum { WASM_LOG_LEVEL_VERBOSE = 4 } log_level_t; +typedef struct SharedHeapInitArgs { + uint32_t size; +} SharedHeapInitArgs; + /** * Initialize the WASM runtime environment, and also initialize * the memory allocator with system allocator, which calls os_malloc @@ -565,6 +581,12 @@ WASM_RUNTIME_API_EXTERN wasm_module_t wasm_runtime_load_ex(uint8_t *buf, uint32_t size, const LoadArgs *args, char *error_buf, uint32_t error_buf_size); +/** + * Resolve symbols for a previously loaded WASM module. Only useful when the + * module was loaded with LoadArgs::no_resolve set to true + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_resolve_symbols(wasm_module_t module); /** * Load a WASM module from a specified WASM or AOT section list. * @@ -939,6 +961,100 @@ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_module_inst(wasm_exec_env_t exec_env, const wasm_module_inst_t module_inst); +/** + * @brief Lookup a memory instance by name + * + * @param module_inst The module instance + * @param name The name of the memory instance + * + * @return The memory instance if found, NULL otherwise + */ +WASM_RUNTIME_API_EXTERN wasm_memory_inst_t +wasm_runtime_lookup_memory(const wasm_module_inst_t module_inst, + const char *name); + +/** + * @brief Get the default memory instance + * + * @param module_inst The module instance + * + * @return The memory instance if found, NULL otherwise + */ +WASM_RUNTIME_API_EXTERN wasm_memory_inst_t +wasm_runtime_get_default_memory(const wasm_module_inst_t module_inst); + +/** + * @brief Get a memory instance by index + * + * @param module_inst The module instance + * @param index The index of the memory instance + * + * @return The memory instance if found, NULL otherwise + */ +WASM_RUNTIME_API_EXTERN wasm_memory_inst_t +wasm_runtime_get_memory(const wasm_module_inst_t module_inst, uint32_t index); + +/** + * @brief Get the current number of pages for a memory instance + * + * @param memory_inst The memory instance + * + * @return The current number of pages + */ +WASM_RUNTIME_API_EXTERN uint64_t +wasm_memory_get_cur_page_count(const wasm_memory_inst_t memory_inst); + +/** + * @brief Get the maximum number of pages for a memory instance + * + * @param memory_inst The memory instance + * + * @return The maximum number of pages + */ +WASM_RUNTIME_API_EXTERN uint64_t +wasm_memory_get_max_page_count(const wasm_memory_inst_t memory_inst); + +/** + * @brief Get the number of bytes per page for a memory instance + * + * @param memory_inst The memory instance + * + * @return The number of bytes per page + */ +WASM_RUNTIME_API_EXTERN uint64_t +wasm_memory_get_bytes_per_page(const wasm_memory_inst_t memory_inst); + +/** + * @brief Get the shared status for a memory instance + * + * @param memory_inst The memory instance + * + * @return True if shared, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_memory_get_shared(const wasm_memory_inst_t memory_inst); + +/** + * @brief Get the base address for a memory instance + * + * @param memory_inst The memory instance + * + * @return The base address on success, false otherwise + */ +WASM_RUNTIME_API_EXTERN void * +wasm_memory_get_base_address(const wasm_memory_inst_t memory_inst); + +/** + * @brief Enlarge a memory instance by a number of pages + * + * @param memory_inst The memory instance + * @param inc_page_count The number of pages to add + * + * @return True if successful, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_memory_enlarge(wasm_memory_inst_t memory_inst, uint64_t inc_page_count); + /** * Call the given WASM function of a WASM module instance with * arguments (bytecode and AoT). @@ -1050,8 +1166,8 @@ wasm_application_execute_main(wasm_module_inst_t module_inst, int32_t argc, char *argv[]); /** - * Find the specified function in argv[0] from a WASM module instance - * and execute that function. + * Find the specified function from a WASM module instance and execute + * that function. * * @param module_inst the WASM module instance * @param name the name of the function to execute. @@ -1639,6 +1755,26 @@ wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void *user_data); WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_user_data(wasm_exec_env_t exec_env); +/** + * Set native stack boundary to execution environment, if it is set, + * it will be used instead of getting the boundary with the platform + * layer API when calling wasm functions. This is useful for some + * fiber cases. + * + * Note: unlike setting the boundary by runtime, this API doesn't add + * the WASM_STACK_GUARD_SIZE(see comments in core/config.h) to the + * exec_env's native_stack_boundary to reserve bytes to the native + * thread stack boundary, which is used to throw native stack overflow + * exception if the guard boundary is reached. Developer should ensure + * that enough guard bytes are kept. + * + * @param exec_env the execution environment + * @param native_stack_boundary the user data to be set + */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_native_stack_boundary(wasm_exec_env_t exec_env, + uint8_t *native_stack_boundary); + /** * Dump runtime memory consumption, including: * Exec env memory consumption @@ -2110,6 +2246,60 @@ wasm_runtime_detect_native_stack_overflow_size(wasm_exec_env_t exec_env, WASM_RUNTIME_API_EXTERN bool wasm_runtime_is_underlying_binary_freeable(const wasm_module_t module); +/** + * Create a shared heap + * + * @param init_args the initialization arguments + * @return the shared heap created + */ +WASM_RUNTIME_API_EXTERN wasm_shared_heap_t +wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args); + +/** + * Attach a shared heap to a module instance + * + * @param module_inst the module instance + * @param shared_heap the shared heap + * @return true if success, false if failed + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_attach_shared_heap(wasm_module_inst_t module_inst, + wasm_shared_heap_t shared_heap); + +/** + * Detach a shared heap from a module instance + * + * @param module_inst the module instance + */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_detach_shared_heap(wasm_module_inst_t module_inst); + +/** + * Allocate memory from a shared heap + * + * @param module_inst the module instance + * @param size required memory size + * @param p_native_addr native address of allocated memory + * + * @return return the allocated memory address, which re-uses part of the wasm + * address space and is in the range of [UINT32 - shared_heap_size + 1, UINT32] + * (when the wasm memory is 32-bit) or [UINT64 - shared_heap_size + 1, UINT64] + * (when the wasm memory is 64-bit). Note that it is not an absolute address. + * Return non-zero if success, zero if failed. + */ +WASM_RUNTIME_API_EXTERN uint64_t +wasm_runtime_shared_heap_malloc(wasm_module_inst_t module_inst, uint64_t size, + void **p_native_addr); + +/** + * Free the memory allocated from shared heap + * + * @param module_inst the module instance + * @param ptr the offset in wasm app + */ +WASM_RUNTIME_API_EXTERN void +wasm_runtime_shared_heap_free(wasm_module_inst_t module_inst, uint64_t ptr); + #ifdef __cplusplus } #endif diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index e043465d4..6023b0702 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -93,6 +93,10 @@ extern "C" { #define MAX_PAGE_COUNT_FLAG 0x01 #define SHARED_MEMORY_FLAG 0x02 #define MEMORY64_FLAG 0x04 +#define MAX_TABLE_SIZE_FLAG 0x01 +/* the shared flag for table is not actual used now */ +#define SHARED_TABLE_FLAG 0x02 +#define TABLE64_FLAG 0x04 /** * In the multi-memory proposal, the memarg in loads and stores are @@ -494,6 +498,7 @@ typedef struct WASMTableType { * 0: no max size and not shared * 1: has max size * 2: shared + * 4: table64 */ uint8 flags; bool possible_grow; @@ -520,6 +525,7 @@ typedef uint64 mem_offset_t; typedef uint32 mem_offset_t; #define PR_MEM_OFFSET PRIu32 #endif +typedef mem_offset_t tbl_elem_idx_t; typedef struct WASMMemory { uint32 flags; @@ -976,8 +982,9 @@ struct WASMModule { uint64 buf_code_size; #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_FAST_JIT != 0 \ - || WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_JIT != 0 +#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_FAST_JIT != 0 \ + || WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 uint8 *load_addr; uint64 load_size; #endif @@ -1238,6 +1245,9 @@ wasm_value_type_size_internal(uint8 value_type, uint8 pointer_size) else { bh_assert(0); } +#if WASM_ENABLE_GC == 0 + (void)pointer_size; +#endif return 0; } diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 4a8ba4e2c..7041fd89c 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -46,6 +46,28 @@ typedef float64 CellType_F64; #define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory) #endif +#if WASM_ENABLE_SHARED_HEAP != 0 +#if WASM_ENABLE_MULTI_MEMORY != 0 +/* Only enable shared heap for the default memory */ +#define is_default_memory (memidx == 0) +#else +#define is_default_memory true +#endif +#define app_addr_in_shared_heap(app_addr, bytes) \ + (shared_heap && is_default_memory && (app_addr) >= shared_heap_start_off \ + && (app_addr) <= shared_heap_end_off - bytes + 1) + +#define shared_heap_addr_app_to_native(app_addr, native_addr) \ + native_addr = shared_heap_base_addr + ((app_addr)-shared_heap_start_off) + +#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) \ + if (app_addr_in_shared_heap(app_addr, bytes)) \ + shared_heap_addr_app_to_native(app_addr, native_addr); \ + else +#else +#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) +#endif + #if WASM_ENABLE_MEMORY64 == 0 #if (!defined(OS_ENABLE_HW_BOUND_CHECK) \ @@ -53,6 +75,7 @@ typedef float64 CellType_F64; #define CHECK_MEMORY_OVERFLOW(bytes) \ do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \ /* If offset1 is in valid range, maddr must also \ be in valid range, no need to check it again. */ \ @@ -64,6 +87,7 @@ typedef float64 CellType_F64; #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ do { \ uint64 offset1 = (uint32)(start); \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \ /* App heap space is not valid space for \ bulk memory operation */ \ @@ -71,18 +95,24 @@ typedef float64 CellType_F64; else \ goto out_of_bounds; \ } while (0) + #else /* else of !defined(OS_ENABLE_HW_BOUND_CHECK) || \ WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ -#define CHECK_MEMORY_OVERFLOW(bytes) \ - do { \ - uint64 offset1 = (uint64)offset + (uint64)addr; \ - maddr = memory->memory_data + offset1; \ + +#define CHECK_MEMORY_OVERFLOW(bytes) \ + do { \ + uint64 offset1 = (uint64)offset + (uint64)addr; \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ + maddr = memory->memory_data + offset1; \ } while (0) -#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ - do { \ - maddr = memory->memory_data + (uint32)(start); \ +#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ + do { \ + uint64 offset1 = (uint32)(start); \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ + maddr = memory->memory_data + offset1; \ } while (0) + #endif /* end of !defined(OS_ENABLE_HW_BOUND_CHECK) || \ WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ @@ -91,6 +121,7 @@ typedef float64 CellType_F64; #define CHECK_MEMORY_OVERFLOW(bytes) \ do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ /* If memory64 is enabled, offset1, offset1 + bytes can overflow */ \ if (disable_bounds_checks \ || (offset1 >= offset && offset1 + bytes >= offset1 \ @@ -99,9 +130,11 @@ typedef float64 CellType_F64; else \ goto out_of_bounds; \ } while (0) + #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ do { \ uint64 offset1 = (uint64)(start); \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ /* If memory64 is enabled, offset1 + bytes can overflow */ \ if (disable_bounds_checks \ || (offset1 + bytes >= offset1 \ @@ -511,9 +544,9 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) #endif #if WASM_ENABLE_MEMORY64 != 0 -#define PUSH_MEM_OFFSET(value) \ +#define COND_PUSH_TEMPLATE(cond, value) \ do { \ - if (is_memory64) { \ + if (cond) { \ PUT_I64_TO_ADDR(frame_sp, value); \ frame_sp += 2; \ } \ @@ -521,8 +554,11 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) *(int32 *)frame_sp++ = (int32)(value); \ } \ } while (0) +#define PUSH_MEM_OFFSET(value) COND_PUSH_TEMPLATE(is_memory64, value) +#define PUSH_TBL_ELEM_IDX(value) COND_PUSH_TEMPLATE(is_table64, value) #else #define PUSH_MEM_OFFSET(value) PUSH_I32(value) +#define PUSH_TBL_ELEM_IDX(value) PUSH_I32(value) #endif #define PUSH_PAGE_COUNT(value) PUSH_MEM_OFFSET(value) @@ -558,8 +594,10 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) #if WASM_ENABLE_MEMORY64 != 0 #define POP_MEM_OFFSET() (is_memory64 ? POP_I64() : POP_I32()) +#define POP_TBL_ELEM_IDX() (is_table64 ? POP_I64() : POP_I32()) #else #define POP_MEM_OFFSET() POP_I32() +#define POP_TBL_ELEM_IDX() POP_I32() #endif #define POP_PAGE_COUNT() POP_MEM_OFFSET() @@ -1562,7 +1600,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 opcode; uint32 i, depth, cond, count, fidx, tidx, lidx, frame_size = 0; uint32 all_cell_num = 0; - int32 val; + tbl_elem_idx_t val; uint8 *else_addr, *end_addr, *maddr = NULL; uint32 local_idx, local_offset, global_idx; uint8 local_type, *global_addr; @@ -1602,9 +1640,26 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* TODO: multi-memories for now assuming the memory idx type is consistent * across multi-memories */ bool is_memory64 = false; + bool is_table64 = false; if (memory) is_memory64 = memory->is_memory64; #endif +#if WASM_ENABLE_SHARED_HEAP != 0 + WASMSharedHeap *shared_heap = module->e->shared_heap; + uint8 *shared_heap_base_addr = shared_heap ? shared_heap->base_addr : NULL; +#if WASM_ENABLE_MEMORY64 != 0 + uint64 shared_heap_start_off = + shared_heap ? (is_memory64 ? shared_heap->start_off_mem64 + : shared_heap->start_off_mem32) + : 0; + uint64 shared_heap_end_off = + shared_heap ? (is_memory64 ? UINT64_MAX : UINT32_MAX) : 0; +#else + uint64 shared_heap_start_off = + shared_heap ? shared_heap->start_off_mem32 : 0; + uint64 shared_heap_end_off = shared_heap ? UINT32_MAX : 0; +#endif +#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */ #if WASM_ENABLE_MULTI_MEMORY != 0 uint32 memidx = 0; uint32 memidx_cached = (uint32)-1; @@ -2315,7 +2370,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /** * type check. compiler will make sure all like - * (call_indirect (type $x) (i32.const 1)) + * (call_indirect (type $x) (it.const 1)) * the function type has to be defined in the module also * no matter it is used or not */ @@ -2334,9 +2389,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* clang-format on */ tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif - val = POP_I32(); - if ((uint32)val >= tbl_inst->cur_size) { + val = POP_TBL_ELEM_IDX(); + if (val >= tbl_inst->cur_size) { wasm_set_exception(module, "undefined element"); goto got_exception; } @@ -2482,15 +2540,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_TABLE_GET) { - uint32 tbl_idx, elem_idx; + uint32 tbl_idx; + tbl_elem_idx_t elem_idx; WASMTableInstance *tbl_inst; read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif - elem_idx = POP_I32(); + elem_idx = POP_TBL_ELEM_IDX(); if (elem_idx >= tbl_inst->cur_size) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; @@ -2507,20 +2569,24 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_TABLE_SET) { WASMTableInstance *tbl_inst; - uint32 tbl_idx, elem_idx; + uint32 tbl_idx; + tbl_elem_idx_t elem_idx; table_elem_type_t elem_val; read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif #if WASM_ENABLE_GC == 0 elem_val = POP_I32(); #else elem_val = POP_REF(); #endif - elem_idx = POP_I32(); + elem_idx = POP_TBL_ELEM_IDX(); if (elem_idx >= tbl_inst->cur_size) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; @@ -3455,8 +3521,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, str_obj = (WASMString)wasm_stringref_obj_get_value( stringref_obj); - memory_inst = module->memories[mem_idx]; - maddr = memory_inst->memory_data + addr; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)addr, 1)) + shared_heap_addr_app_to_native((uint64)addr, maddr); + else +#endif + { + memory_inst = module->memories[mem_idx]; + maddr = memory_inst->memory_data + addr; + } if (opcode == WASM_OP_STRING_ENCODE_WTF16) { flag = WTF16; @@ -3623,8 +3696,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); stringview_wtf8_obj = POP_REF(); - memory_inst = module->memories[mem_idx]; - maddr = memory_inst->memory_data + addr; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)addr, 1)) + shared_heap_addr_app_to_native((uint64)addr, maddr); + else +#endif + { + memory_inst = module->memories[mem_idx]; + maddr = memory_inst->memory_data + addr; + } bytes_written = wasm_string_encode( (WASMString)wasm_stringview_wtf8_obj_get_value( @@ -4616,13 +4696,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_MEMORY_GROW) { - uint32 mem_idx, delta, prev_page_count; + uint32 mem_idx, prev_page_count; + mem_offset_t delta; read_leb_memidx(frame_ip, frame_ip_end, mem_idx); prev_page_count = memory->cur_page_count; - delta = (uint32)POP_PAGE_COUNT(); + delta = POP_PAGE_COUNT(); - if (!wasm_enlarge_memory_with_idx(module, delta, mem_idx)) { + if ( +#if WASM_ENABLE_MEMORY64 != 0 + delta > UINT32_MAX || +#endif + !wasm_enlarge_memory_with_idx(module, (uint32)delta, + mem_idx)) { /* failed to memory.grow, return -1 */ PUSH_PAGE_COUNT(-1); } @@ -5651,9 +5737,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr); #else - if ((uint64)(uint32)addr + bytes > linear_mem_size) - goto out_of_bounds; - maddr = memory->memory_data + (uint32)addr; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)(uint32)addr, + bytes)) + shared_heap_addr_app_to_native((uint64)(uint32)addr, + maddr); + else +#endif + { + if ((uint64)(uint32)addr + bytes > linear_mem_size) + goto out_of_bounds; + maddr = memory->memory_data + (uint32)addr; + } #endif if (bh_bitmap_get_bit(module->e->common.data_dropped, @@ -5703,15 +5798,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_THREAD_MGR != 0 linear_mem_size = get_linear_mem_size(); #endif + + dlen = linear_mem_size - dst; + /* dst boundary check */ #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); -#else - if ((uint64)dst + len > linear_mem_size) - goto out_of_bounds; - mdst = memory->memory_data + dst; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)dst, len)) + dlen = shared_heap_end_off - dst + 1; #endif - dlen = linear_mem_size - dst; +#else /* else of OS_ENABLE_HW_BOUND_CHECK */ +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)dst, len)) { + shared_heap_addr_app_to_native((uint64)dst, mdst); + dlen = shared_heap_end_off - dst + 1; + } + else +#endif + { + if ((uint64)dst + len > linear_mem_size) + goto out_of_bounds; + mdst = memory->memory_data + dst; + } +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ #if WASM_ENABLE_MULTI_MEMORY != 0 /* src memidx */ @@ -5727,9 +5837,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc); #else - if ((uint64)src + len > linear_mem_size) - goto out_of_bounds; - msrc = memory->memory_data + src; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)src, len)) + shared_heap_addr_app_to_native((uint64)src, msrc); + else +#endif + { + if ((uint64)src + len > linear_mem_size) + goto out_of_bounds; + msrc = memory->memory_data + src; + } #endif #if WASM_ENABLE_MEMORY64 == 0 @@ -5739,6 +5856,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* use memmove when memory64 is enabled since len may be larger than UINT32_MAX */ memmove(mdst, msrc, len); + (void)dlen; #endif break; } @@ -5765,9 +5883,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); #else - if ((uint64)(uint32)dst + len > linear_mem_size) - goto out_of_bounds; - mdst = memory->memory_data + (uint32)dst; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)(uint32)dst, len)) + shared_heap_addr_app_to_native((uint64)(uint32)dst, + mdst); + else +#endif + { + if ((uint64)(uint32)dst + len > linear_mem_size) + goto out_of_bounds; + mdst = memory->memory_data + (uint32)dst; + } #endif memset(mdst, fill_val, len); @@ -5777,8 +5903,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 case WASM_OP_TABLE_INIT: { - uint32 tbl_idx, elem_idx; - uint32 n, s, d; + uint32 tbl_idx; + tbl_elem_idx_t elem_idx, d; + uint32 n, s; WASMTableInstance *tbl_inst; table_elem_type_t *table_elems; InitializerExpression *tbl_seg_init_values = NULL, @@ -5792,10 +5919,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(tbl_idx < module->module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif n = (uint32)POP_I32(); s = (uint32)POP_I32(); - d = (uint32)POP_I32(); + d = (tbl_elem_idx_t)POP_TBL_ELEM_IDX(); if (!bh_bitmap_get_bit(module->e->common.elem_dropped, elem_idx)) { @@ -5808,8 +5938,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, .value_count; } - if (offset_len_out_of_bounds(s, n, tbl_seg_len) - || offset_len_out_of_bounds(d, n, + /* TODO: memory64 current implementation of table64 + * still assumes the max table size UINT32_MAX + */ + if ( +#if WASM_ENABLE_MEMORY64 != 0 + d > UINT32_MAX || +#endif + offset_len_out_of_bounds(s, n, tbl_seg_len) + || offset_len_out_of_bounds((uint32)d, n, tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); @@ -5863,7 +6000,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, case WASM_OP_TABLE_COPY: { uint32 src_tbl_idx, dst_tbl_idx; - uint32 n, s, d; + tbl_elem_idx_t n, s, d; WASMTableInstance *src_tbl_inst, *dst_tbl_inst; read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx); @@ -5876,14 +6013,29 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx); - n = (uint32)POP_I32(); - s = (uint32)POP_I32(); - d = (uint32)POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = src_tbl_inst->is_table64 + && dst_tbl_inst->is_table64; +#endif + n = (tbl_elem_idx_t)POP_TBL_ELEM_IDX(); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = src_tbl_inst->is_table64; +#endif + s = (tbl_elem_idx_t)POP_TBL_ELEM_IDX(); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = dst_tbl_inst->is_table64; +#endif + d = (tbl_elem_idx_t)POP_TBL_ELEM_IDX(); - if (offset_len_out_of_bounds(d, n, + if ( +#if WASM_ENABLE_MEMORY64 != 0 + n > UINT32_MAX || s > UINT32_MAX || d > UINT32_MAX + || +#endif + offset_len_out_of_bounds((uint32)d, (uint32)n, dst_tbl_inst->cur_size) || offset_len_out_of_bounds( - s, n, src_tbl_inst->cur_size)) { + (uint32)s, (uint32)n, src_tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; @@ -5906,28 +6058,37 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, case WASM_OP_TABLE_GROW: { WASMTableInstance *tbl_inst; - uint32 tbl_idx, n, orig_tbl_sz; + uint32 tbl_idx, orig_tbl_sz; + tbl_elem_idx_t n; table_elem_type_t init_val; read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif orig_tbl_sz = tbl_inst->cur_size; - n = POP_I32(); + n = POP_TBL_ELEM_IDX(); #if WASM_ENABLE_GC == 0 init_val = POP_I32(); #else init_val = POP_REF(); #endif - if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) { - PUSH_I32(-1); + if ( +#if WASM_ENABLE_MEMORY64 != 0 + n > UINT32_MAX || +#endif + !wasm_enlarge_table(module, tbl_idx, (uint32)n, + init_val)) { + PUSH_TBL_ELEM_IDX(-1); } else { - PUSH_I32(orig_tbl_sz); + PUSH_TBL_ELEM_IDX(orig_tbl_sz); } break; } @@ -5940,13 +6101,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif - PUSH_I32(tbl_inst->cur_size); + PUSH_TBL_ELEM_IDX(tbl_inst->cur_size); break; } case WASM_OP_TABLE_FILL: { - uint32 tbl_idx, n; + uint32 tbl_idx; + tbl_elem_idx_t n, elem_idx; WASMTableInstance *tbl_inst; table_elem_type_t fill_val; @@ -5954,24 +6119,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif - n = POP_I32(); + n = POP_TBL_ELEM_IDX(); #if WASM_ENABLE_GC == 0 fill_val = POP_I32(); #else fill_val = POP_REF(); #endif - i = POP_I32(); + elem_idx = POP_TBL_ELEM_IDX(); - if (offset_len_out_of_bounds(i, n, + if ( +#if WASM_ENABLE_MEMORY64 != 0 + n > UINT32_MAX || elem_idx > UINT32_MAX || +#endif + offset_len_out_of_bounds((uint32)elem_idx, + (uint32)n, tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; } - for (; n != 0; i++, n--) { - tbl_inst->elems[i] = fill_val; + for (; n != 0; elem_idx++, n--) { + tbl_inst->elems[elem_idx] = fill_val; } break; } @@ -6554,7 +6727,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 if (memory) - linear_mem_size = get_linear_mem_size(); + linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); #endif if (wasm_copy_exception(module, NULL)) { #if WASM_ENABLE_EXCE_HANDLING != 0 diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 51963759f..531468282 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -37,11 +37,28 @@ typedef float64 CellType_F64; #define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory) #endif +#if WASM_ENABLE_SHARED_HEAP != 0 +#define app_addr_in_shared_heap(app_addr, bytes) \ + (shared_heap && (app_addr) >= shared_heap_start_off \ + && (app_addr) <= shared_heap_end_off - bytes + 1) + +#define shared_heap_addr_app_to_native(app_addr, native_addr) \ + native_addr = shared_heap_base_addr + ((app_addr)-shared_heap_start_off) + +#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) \ + if (app_addr_in_shared_heap(app_addr, bytes)) \ + shared_heap_addr_app_to_native(app_addr, native_addr); \ + else +#else +#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) +#endif + #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 #define CHECK_MEMORY_OVERFLOW(bytes) \ do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \ /* If offset1 is in valid range, maddr must also \ be in valid range, no need to check it again. */ \ @@ -53,6 +70,7 @@ typedef float64 CellType_F64; #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ do { \ uint64 offset1 = (uint32)(start); \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \ /* App heap space is not valid space for \ bulk memory operation */ \ @@ -61,15 +79,18 @@ typedef float64 CellType_F64; goto out_of_bounds; \ } while (0) #else -#define CHECK_MEMORY_OVERFLOW(bytes) \ - do { \ - uint64 offset1 = (uint64)offset + (uint64)addr; \ - maddr = memory->memory_data + offset1; \ +#define CHECK_MEMORY_OVERFLOW(bytes) \ + do { \ + uint64 offset1 = (uint64)offset + (uint64)addr; \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ + maddr = memory->memory_data + offset1; \ } while (0) -#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ - do { \ - maddr = memory->memory_data + (uint32)(start); \ +#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ + do { \ + uint64 offset1 = (uint32)(start); \ + CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \ + maddr = memory->memory_data + offset1; \ } while (0) #endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ @@ -1516,6 +1537,24 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 bool is_return_call = false; #endif +#if WASM_ENABLE_SHARED_HEAP != 0 + WASMSharedHeap *shared_heap = module->e ? module->e->shared_heap : NULL; + uint8 *shared_heap_base_addr = shared_heap ? shared_heap->base_addr : NULL; + /* +#if WASM_ENABLE_MEMORY64 != 0 + uint64 shared_heap_start_off = + shared_heap ? (is_memory64 ? shared_heap->start_off_mem64 + : shared_heap->start_off_mem32) + : 0; + uint64 shared_heap_end_off = + shared_heap ? (is_memory64 ? UINT64_MAX : UINT32_MAX) : 0; +#else + */ /* TODO: uncomment the code when memory64 is enabled for fast-interp */ + uint64 shared_heap_start_off = + shared_heap ? shared_heap->start_off_mem32 : 0; + uint64 shared_heap_end_off = shared_heap ? UINT32_MAX : 0; +/* #endif */ +#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */ #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -2831,8 +2870,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, str_obj = (WASMString)wasm_stringref_obj_get_value( stringref_obj); - memory_inst = module->memories[mem_idx]; - maddr = memory_inst->memory_data + addr; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)addr, 1)) + shared_heap_addr_app_to_native((uint64)addr, maddr); + else +#endif + { + memory_inst = module->memories[mem_idx]; + maddr = memory_inst->memory_data + addr; + } if (opcode == WASM_OP_STRING_ENCODE_WTF16) { flag = WTF16; @@ -2999,8 +3045,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); stringview_wtf8_obj = POP_REF(); - memory_inst = module->memories[mem_idx]; - maddr = memory_inst->memory_data + addr; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)addr, 1)) + shared_heap_addr_app_to_native((uint64)addr, maddr); + else +#endif + { + memory_inst = module->memories[mem_idx]; + maddr = memory_inst->memory_data + addr; + } bytes_written = wasm_string_encode( (WASMString)wasm_stringview_wtf8_obj_get_value( @@ -4985,9 +5038,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr); #else - if ((uint64)(uint32)addr + bytes > linear_mem_size) - goto out_of_bounds; - maddr = memory->memory_data + (uint32)addr; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)(uint32)addr, + bytes)) + shared_heap_addr_app_to_native((uint64)(uint32)addr, + maddr); + else +#endif + { + if ((uint64)(uint32)addr + bytes > linear_mem_size) + goto out_of_bounds; + maddr = memory->memory_data + (uint32)addr; + } #endif if (bh_bitmap_get_bit(module->e->common.data_dropped, segment)) { @@ -5020,6 +5082,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 dst, src, len; uint8 *mdst, *msrc; + uint64 dlen; len = POP_I32(); src = POP_I32(); @@ -5029,22 +5092,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, linear_mem_size = get_linear_mem_size(); #endif + dlen = linear_mem_size - dst; + #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc); CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); -#else - if ((uint64)(uint32)src + len > linear_mem_size) - goto out_of_bounds; - msrc = memory->memory_data + (uint32)src; - - if ((uint64)(uint32)dst + len > linear_mem_size) - goto out_of_bounds; - mdst = memory->memory_data + (uint32)dst; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)dst, len)) + dlen = shared_heap_end_off - dst + 1; #endif +#else /* else of OS_ENABLE_HW_BOUND_CHECK */ +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)src, len)) + shared_heap_addr_app_to_native((uint64)src, msrc); + else +#endif + { + if ((uint64)(uint32)src + len > linear_mem_size) + goto out_of_bounds; + msrc = memory->memory_data + (uint32)src; + } + +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)dst, len)) { + shared_heap_addr_app_to_native((uint64)dst, mdst); + dlen = shared_heap_end_off - dst + 1; + } + else +#endif + { + if ((uint64)(uint32)dst + len > linear_mem_size) + goto out_of_bounds; + mdst = memory->memory_data + (uint32)dst; + } +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ /* allowing the destination and source to overlap */ - bh_memmove_s(mdst, (uint32)(linear_mem_size - dst), - msrc, len); + bh_memmove_s(mdst, (uint32)dlen, msrc, len); break; } case WASM_OP_MEMORY_FILL: @@ -5063,9 +5147,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); #else - if ((uint64)(uint32)dst + len > linear_mem_size) - goto out_of_bounds; - mdst = memory->memory_data + (uint32)dst; +#if WASM_ENABLE_SHARED_HEAP != 0 + if (app_addr_in_shared_heap((uint64)(uint32)dst, len)) + shared_heap_addr_app_to_native((uint64)(uint32)dst, + mdst); + else +#endif + { + if ((uint64)(uint32)dst + len > linear_mem_size) + goto out_of_bounds; + mdst = memory->memory_data + (uint32)dst; + } #endif memset(mdst, fill_val, len); @@ -5902,7 +5994,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 if (memory) - linear_mem_size = get_linear_mem_size(); + linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); #endif if (wasm_copy_exception(module, NULL)) goto got_exception; @@ -6030,7 +6122,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_LABELS_AS_VALUES != 0 void ** -wasm_interp_get_handle_table() +wasm_interp_get_handle_table(void) { WASMModuleInstance module; memset(&module, 0, sizeof(WASMModuleInstance)); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 13947ac82..ae823d7be 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -4,8 +4,7 @@ */ #include "wasm_loader.h" -#include "bh_common.h" -#include "bh_log.h" +#include "bh_platform.h" #include "wasm.h" #include "wasm_opcode.h" #include "wasm_runtime.h" @@ -51,6 +50,18 @@ has_module_memory64(WASMModule *module) return false; } + +static bool +is_table_64bit(WASMModule *module, uint32 table_idx) +{ + if (table_idx < module->import_table_count) + return !!(module->import_tables[table_idx].u.table.table_type.flags + & TABLE64_FLAG); + else + return !!(module->tables[table_idx].table_type.flags & TABLE64_FLAG); + + return false; +} #endif static void @@ -2201,10 +2212,14 @@ fail: } static void -adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size) +adjust_table_max_size(bool is_table64, uint32 init_size, uint32 max_size_flag, + uint32 *max_size) { uint32 default_max_size; + /* TODO: current still use UINT32_MAX as upper limit for table size to keep + * ABI unchanged */ + (void)is_table64; if (UINT32_MAX / 2 > init_size) default_max_size = init_size * 2; else @@ -2246,60 +2261,6 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name, #endif #if WASM_ENABLE_MULTI_MODULE != 0 -static WASMFunction * -wasm_loader_resolve_function(const char *module_name, const char *function_name, - const WASMFuncType *expected_function_type, - char *error_buf, uint32 error_buf_size) -{ - WASMModuleCommon *module_reg; - WASMFunction *function = NULL; - WASMExport *export = NULL; - WASMModule *module = NULL; - WASMFuncType *target_function_type = NULL; - - module_reg = wasm_runtime_find_module_registered(module_name); - if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { - LOG_DEBUG("can not find a module named %s for function %s", module_name, - function_name); - set_error_buf(error_buf, error_buf_size, "unknown import"); - return NULL; - } - - module = (WASMModule *)module_reg; - export = - wasm_loader_find_export(module, module_name, function_name, - EXPORT_KIND_FUNC, error_buf, error_buf_size); - if (!export) { - return NULL; - } - - /* resolve function type and function */ - if (export->index < module->import_function_count) { - target_function_type = - module->import_functions[export->index].u.function.func_type; - function = module->import_functions[export->index] - .u.function.import_func_linked; - } - else { - target_function_type = - module->functions[export->index - module->import_function_count] - ->func_type; - function = - module->functions[export->index - module->import_function_count]; - } - - /* check function type */ - if (!wasm_type_equal((WASMType *)expected_function_type, - (WASMType *)target_function_type, module->types, - module->type_count)) { - LOG_DEBUG("%s.%s failed the type check", module_name, function_name); - set_error_buf(error_buf, error_buf_size, "incompatible import type"); - return NULL; - } - - return function; -} - static WASMTable * wasm_loader_resolve_table(const char *module_name, const char *table_name, uint32 init_size, uint32 max_size, char *error_buf, @@ -2474,7 +2435,8 @@ wasm_loader_resolve_tag(const char *module_name, const char *tag_name, } /* check function type */ - if (!wasm_type_equal(expected_tag_type, tag->tag_type)) { + if (!wasm_type_equal(expected_tag_type, tag->tag_type, module->types, + module->type_count)) { LOG_DEBUG("%s.%s failed the type check", module_name, tag_name); set_error_buf(error_buf, error_buf_size, "incompatible import type"); return NULL; @@ -2493,21 +2455,11 @@ static bool load_function_import(const uint8 **p_buf, const uint8 *buf_end, const WASMModule *parent_module, const char *sub_module_name, const char *function_name, - WASMFunctionImport *function, char *error_buf, - uint32 error_buf_size) + WASMFunctionImport *function, bool no_resolve, + char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; uint32 declare_type_index = 0; - WASMFuncType *declare_func_type = NULL; - WASMFunction *linked_func = NULL; -#if WASM_ENABLE_MULTI_MODULE != 0 - WASMModule *sub_module = NULL; - bool is_built_in_module = false; -#endif - const char *linked_signature = NULL; - void *linked_attachment = NULL; - bool linked_call_conv_raw = false; - bool is_native_symbol = false; read_leb_uint32(p, p_end, declare_type_index); *p_buf = p; @@ -2526,43 +2478,19 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end, parent_module->types, parent_module->type_count, declare_type_index); #endif - declare_func_type = + function->func_type = (WASMFuncType *)parent_module->types[declare_type_index]; - /* lookup registered native symbols first */ - linked_func = wasm_native_resolve_symbol( - sub_module_name, function_name, declare_func_type, &linked_signature, - &linked_attachment, &linked_call_conv_raw); - if (linked_func) { - is_native_symbol = true; - } -#if WASM_ENABLE_MULTI_MODULE != 0 - else { - if (!(is_built_in_module = - wasm_runtime_is_built_in_module(sub_module_name))) { - sub_module = (WASMModule *)wasm_runtime_load_depended_module( - (WASMModuleCommon *)parent_module, sub_module_name, error_buf, - error_buf_size); - } - if (is_built_in_module || sub_module) - linked_func = wasm_loader_resolve_function( - sub_module_name, function_name, declare_func_type, error_buf, - error_buf_size); - } -#endif - function->module_name = (char *)sub_module_name; function->field_name = (char *)function_name; - function->func_type = declare_func_type; - /* func_ptr_linked is for native registered symbol */ - function->func_ptr_linked = is_native_symbol ? linked_func : NULL; - function->signature = linked_signature; - function->attachment = linked_attachment; - function->call_conv_raw = linked_call_conv_raw; -#if WASM_ENABLE_MULTI_MODULE != 0 - function->import_module = is_native_symbol ? NULL : sub_module; - function->import_func_linked = is_native_symbol ? NULL : linked_func; -#endif + function->attachment = NULL; + function->signature = NULL; + function->call_conv_raw = false; + + /* lookup registered native symbols first */ + if (!no_resolve) { + wasm_resolve_import_func(parent_module, function); + } return true; fail: return false; @@ -2586,9 +2514,9 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, const char *table_name, WASMTableImport *table, char *error_buf, uint32 error_buf_size) { - const uint8 *p = *p_buf, *p_end = buf_end; - uint32 declare_elem_type = 0, declare_max_size_flag = 0, - declare_init_size = 0, declare_max_size = 0; + const uint8 *p = *p_buf, *p_end = buf_end, *p_org; + uint32 declare_elem_type = 0, table_flag = 0, declare_init_size = 0, + declare_max_size = 0; #if WASM_ENABLE_MULTI_MODULE != 0 WASMModule *sub_module = NULL; WASMTable *linked_table = NULL; @@ -2597,6 +2525,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, WASMRefType ref_type; bool need_ref_type_map; #endif + bool is_table64 = false; #if WASM_ENABLE_GC == 0 CHECK_BUF(p, p_end, 1); @@ -2635,23 +2564,29 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, #endif #endif /* end of WASM_ENABLE_GC == 0 */ - read_leb_uint32(p, p_end, declare_max_size_flag); - if (declare_max_size_flag > 1) { - set_error_buf(error_buf, error_buf_size, "integer too large"); + p_org = p; + read_leb_uint32(p, p_end, table_flag); + is_table64 = table_flag & TABLE64_FLAG; + if (p - p_org > 1) { + LOG_VERBOSE("integer representation too long(import table)"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } + + if (!wasm_table_check_flags(table_flag, error_buf, error_buf_size, false)) { return false; } read_leb_uint32(p, p_end, declare_init_size); - - if (declare_max_size_flag) { + if (table_flag & MAX_TABLE_SIZE_FLAG) { read_leb_uint32(p, p_end, declare_max_size); if (!check_table_max_size(declare_init_size, declare_max_size, error_buf, error_buf_size)) return false; } - adjust_table_max_size(declare_init_size, declare_max_size_flag, - &declare_max_size); + adjust_table_max_size(is_table64, declare_init_size, + table_flag & MAX_TABLE_SIZE_FLAG, &declare_max_size); *p_buf = p; @@ -2669,7 +2604,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, declare_elem_type = linked_table->table_type.elem_type; declare_init_size = linked_table->table_type.init_size; declare_max_size = linked_table->table_type.max_size; - declare_max_size_flag = linked_table->table_type.flags; + table_flag = linked_table->table_type.flags; table->import_table_linked = linked_table; table->import_module = sub_module; } @@ -2678,12 +2613,17 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, #endif /* WASM_ENABLE_MULTI_MODULE != 0 */ /* (table (export "table") 10 20 funcref) */ + /* (table (export "table64") 10 20 funcref) */ /* we need this section working in wamrc */ if (!strcmp("spectest", sub_module_name)) { const uint32 spectest_table_init_size = 10; const uint32 spectest_table_max_size = 20; - if (strcmp("table", table_name)) { + if (strcmp("table", table_name) +#if WASM_ENABLE_MEMORY64 != 0 + && strcmp("table64", table_name) +#endif + ) { set_error_buf(error_buf, error_buf_size, "incompatible import type or unknown import"); return false; @@ -2703,7 +2643,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, /* now we believe all declaration are ok */ table->table_type.elem_type = declare_elem_type; table->table_type.init_size = declare_init_size; - table->table_type.flags = declare_max_size_flag; + table->table_type.flags = table_flag; table->table_type.max_size = declare_max_size; #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -2796,7 +2736,7 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, read_leb_uint32(p, p_end, mem_flag); is_memory64 = mem_flag & MEMORY64_FLAG; if (p - p_org > 1) { - LOG_VERBOSE("integer representation too long"); + LOG_VERBOSE("integer representation too long(import memory)"); set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } @@ -3111,6 +3051,7 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, WASMRefType ref_type; bool need_ref_type_map; #endif + bool is_table64 = false; #if WASM_ENABLE_GC == 0 CHECK_BUF(p, p_end, 1); @@ -3148,34 +3089,20 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, p_org = p; read_leb_uint32(p, p_end, table->table_type.flags); -#if WASM_ENABLE_SHARED_MEMORY == 0 - if (p - p_org > 1) { - set_error_buf(error_buf, error_buf_size, - "integer representation too long"); - return false; - } - if (table->table_type.flags > 1) { - set_error_buf(error_buf, error_buf_size, "integer too large"); - return false; - } -#else + is_table64 = table->table_type.flags & TABLE64_FLAG; if (p - p_org > 1) { + LOG_VERBOSE("integer representation too long(table)"); set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } - if (table->table_type.flags == 2) { - set_error_buf(error_buf, error_buf_size, "tables cannot be shared"); + + if (!wasm_table_check_flags(table->table_type.flags, error_buf, + error_buf_size, false)) { return false; } - if (table->table_type.flags > 1) { - set_error_buf(error_buf, error_buf_size, "invalid limits flags"); - return false; - } -#endif read_leb_uint32(p, p_end, table->table_type.init_size); - - if (table->table_type.flags) { + if (table->table_type.flags & MAX_TABLE_SIZE_FLAG) { read_leb_uint32(p, p_end, table->table_type.max_size); if (!check_table_max_size(table->table_type.init_size, table->table_type.max_size, error_buf, @@ -3183,7 +3110,8 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, return false; } - adjust_table_max_size(table->table_type.init_size, table->table_type.flags, + adjust_table_max_size(is_table64, table->table_type.init_size, + table->table_type.flags & MAX_TABLE_SIZE_FLAG, &table->table_type.max_size); #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -3215,7 +3143,7 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, read_leb_uint32(p, p_end, memory->flags); is_memory64 = memory->flags & MEMORY64_FLAG; if (p - p_org > 1) { - LOG_VERBOSE("integer representation too long"); + LOG_VERBOSE("integer representation too long(memory)"); set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } @@ -3255,10 +3183,16 @@ fail: return false; } +static int +cmp_export_name(const void *a, const void *b) +{ + return strcmp(*(char **)a, *(char **)b); +} + static bool load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, - bool is_load_from_file_buf, char *error_buf, - uint32 error_buf_size) + bool is_load_from_file_buf, bool no_resolve, + char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end, *p_old; uint32 import_count, name_len, type_index, i, u32, flags; @@ -3441,9 +3375,10 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, case IMPORT_KIND_FUNC: /* import function */ bh_assert(import_functions); import = import_functions++; - if (!load_function_import( - &p, p_end, module, sub_module_name, field_name, - &import->u.function, error_buf, error_buf_size)) { + if (!load_function_import(&p, p_end, module, + sub_module_name, field_name, + &import->u.function, no_resolve, + error_buf, error_buf_size)) { return false; } break; @@ -4124,17 +4059,53 @@ fail: return false; } +static bool +check_duplicate_exports(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ + uint32 i; + bool result = false; + char *names_buf[32], **names = names_buf; + + if (module->export_count > 32) { + names = loader_malloc(module->export_count * sizeof(char *), error_buf, + error_buf_size); + if (!names) { + return result; + } + } + + for (i = 0; i < module->export_count; i++) { + names[i] = module->exports[i].name; + } + + qsort(names, module->export_count, sizeof(char *), cmp_export_name); + + for (i = 1; i < module->export_count; i++) { + if (!strcmp(names[i], names[i - 1])) { + set_error_buf(error_buf, error_buf_size, "duplicate export name"); + goto cleanup; + } + } + + result = true; +cleanup: + if (module->export_count > 32) { + wasm_runtime_free(names); + } + return result; +} + static bool load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, bool is_load_from_file_buf, char *error_buf, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; - uint32 export_count, i, j, index; + uint32 export_count, i, index; uint64 total_size; uint32 str_len; WASMExport *export; - const char *name; read_leb_uint32(p, p_end, export_count); @@ -4160,15 +4131,6 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, str_len); CHECK_BUF(p, p_end, str_len); - for (j = 0; j < i; j++) { - name = module->exports[j].name; - if (strlen(name) == str_len && memcmp(name, p, str_len) == 0) { - set_error_buf(error_buf, error_buf_size, - "duplicate export name"); - return false; - } - } - if (!(export->name = wasm_const_str_list_insert( p, str_len, module, is_load_from_file_buf, error_buf, error_buf_size))) { @@ -4241,6 +4203,10 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } } + + if (!check_duplicate_exports(module, error_buf, error_buf_size)) { + return false; + } } if (p != p_end) { @@ -4488,6 +4454,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; + uint8 table_elem_idx_type; uint32 table_segment_count, i; uint64 total_size; WASMTableSeg *table_segment; @@ -4510,6 +4477,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, "invalid elements segment kind"); return false; } + table_elem_idx_type = VALUE_TYPE_I32; #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 read_leb_uint32(p, p_end, table_segment->mode); @@ -4545,9 +4513,17 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, if (!check_table_index(module, table_segment->table_index, error_buf, error_buf_size)) return false; - if (!load_init_expr( - module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, NULL, error_buf, error_buf_size)) + +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + if (!load_init_expr(module, &p, p_end, + &table_segment->base_offset, + table_elem_idx_type, NULL, error_buf, + error_buf_size)) return false; if (table_segment->mode == 0) { @@ -4595,9 +4571,16 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, &table_segment->table_index, error_buf, error_buf_size)) return false; - if (!load_init_expr( - module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, NULL, error_buf, error_buf_size)) +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + if (!load_init_expr(module, &p, p_end, + &table_segment->base_offset, + table_elem_idx_type, NULL, error_buf, + error_buf_size)) return false; if (!load_elem_type(module, &p, p_end, &table_segment->elem_type, @@ -4649,7 +4632,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, "unknown element segment kind"); return false; } -#else /* else of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */ +#else /* else of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */ /* * like: 00 41 05 0b 04 00 01 00 01 * for: (elem 0 (offset (i32.const 5)) $f1 $f2 $f1 $f2) @@ -4658,8 +4641,14 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, &table_segment->table_index, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (!load_init_expr(module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, NULL, error_buf, + table_elem_idx_type, NULL, error_buf, error_buf_size)) return false; if (!load_func_index_vec(&p, p_end, module, table_segment, @@ -4674,6 +4663,16 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, return false; #endif /* end of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */ +#if WASM_ENABLE_MEMORY64 != 0 + if (table_elem_idx_type == VALUE_TYPE_I64 + && table_segment->base_offset.u.u64 > UINT32_MAX) { + set_error_buf(error_buf, error_buf_size, + "In table64, table base offset can't be " + "larger than UINT32_MAX"); + return false; + } +#endif + #if WASM_ENABLE_WAMR_COMPILER != 0 if (table_segment->elem_type == VALUE_TYPE_EXTERNREF) module->is_ref_types_used = true; @@ -5406,7 +5405,8 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, option.enable_aux_stack_check = true; #if WASM_ENABLE_PERF_PROFILING != 0 || WASM_ENABLE_DUMP_CALL_STACK != 0 \ || WASM_ENABLE_AOT_STACK_FRAME != 0 - option.enable_aux_stack_frame = true; + option.aux_stack_frame_type = AOT_STACK_FRAME_TYPE_STANDARD; + aot_call_stack_features_init_default(&option.call_stack_features); #endif #if WASM_ENABLE_PERF_PROFILING != 0 option.enable_perf_profiling = true; @@ -5415,6 +5415,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, option.enable_memory_profiling = true; option.enable_stack_estimation = true; #endif +#if WASM_ENABLE_SHARED_HEAP != 0 + option.enable_shared_heap = true; +#endif module->comp_ctx = aot_create_comp_context(module->comp_data, &option); if (!module->comp_ctx) { @@ -5750,7 +5753,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, #if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0 void ** -wasm_interp_get_handle_table(); +wasm_interp_get_handle_table(void); static void **handle_table; #endif @@ -5758,7 +5761,7 @@ static void **handle_table; static bool load_from_sections(WASMModule *module, WASMSection *sections, bool is_load_from_file_buf, bool wasm_binary_freeable, - char *error_buf, uint32 error_buf_size) + bool no_resolve, char *error_buf, uint32 error_buf_size) { WASMExport *export; WASMSection *section = sections; @@ -5815,8 +5818,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, break; case SECTION_TYPE_IMPORT: if (!load_import_section(buf, buf_end, module, - reuse_const_strings, error_buf, - error_buf_size)) + reuse_const_strings, no_resolve, + error_buf, error_buf_size)) return false; break; case SECTION_TYPE_FUNC: @@ -6195,6 +6198,12 @@ load_from_sections(WASMModule *module, WASMSection *sections, #endif } +#if WASM_ENABLE_MEMORY64 != 0 + if (!check_memory64_flags_consistency(module, error_buf, error_buf_size, + false)) + return false; +#endif + calculate_global_data_offset(module); #if WASM_ENABLE_FAST_JIT != 0 @@ -6341,7 +6350,7 @@ wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf, if (!module) return NULL; - if (!load_from_sections(module, section_list, false, true, error_buf, + if (!load_from_sections(module, section_list, false, true, false, error_buf, error_buf_size)) { wasm_loader_unload(module); return NULL; @@ -6486,7 +6495,8 @@ static union { static bool load(const uint8 *buf, uint32 size, WASMModule *module, - bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size) + bool wasm_binary_freeable, bool no_resolve, char *error_buf, + uint32 error_buf_size) { const uint8 *buf_end = buf + size; const uint8 *p = buf, *p_end = buf_end; @@ -6517,7 +6527,7 @@ load(const uint8 *buf, uint32 size, WASMModule *module, if (!create_sections(buf, size, §ion_list, error_buf, error_buf_size) || !load_from_sections(module, section_list, true, wasm_binary_freeable, - error_buf, error_buf_size)) { + no_resolve, error_buf, error_buf_size)) { destroy_sections(section_list); return false; } @@ -6693,8 +6703,8 @@ wasm_loader_load(uint8 *buf, uint32 size, module->load_size = size; #endif - if (!load(buf, size, module, args->wasm_binary_freeable, error_buf, - error_buf_size)) { + if (!load(buf, size, module, args->wasm_binary_freeable, args->no_resolve, + error_buf, error_buf_size)) { goto fail; } @@ -9692,6 +9702,7 @@ fail: #define POP_REF(Type) TEMPLATE_POP_REF(Type) #define PUSH_MEM_OFFSET() TEMPLATE_PUSH_REF(mem_offset_type) #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() +#define PUSH_TBL_ELEM_IDX() TEMPLATE_PUSH_REF(table_elem_idx_type) #define POP_I32() TEMPLATE_POP(I32) #define POP_F32() TEMPLATE_POP(F32) @@ -9702,6 +9713,7 @@ fail: #define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF) #define POP_STRINGREF() TEMPLATE_POP(STRINGREF) #define POP_MEM_OFFSET() TEMPLATE_POP_REF(mem_offset_type) +#define POP_TBL_ELEM_IDX() TEMPLATE_POP_REF(table_elem_idx_type) #if WASM_ENABLE_FAST_INTERP != 0 @@ -10887,7 +10899,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; - uint8 *param_types, *local_types, local_type, global_type, mem_offset_type; + uint8 *param_types, *local_types, local_type, global_type, mem_offset_type, + table_elem_idx_type; BlockType func_block_type; uint16 *local_offsets, local_offset; uint32 type_idx, func_idx, local_idx, global_idx, table_idx; @@ -10922,6 +10935,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32; #else mem_offset_type = VALUE_TYPE_I32; + table_elem_idx_type = VALUE_TYPE_I32; #endif uint32 memidx; @@ -12081,8 +12095,13 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif /* skip elem idx */ - POP_I32(); + POP_TBL_ELEM_IDX(); if (type_idx >= module->type_count) { set_error_buf(error_buf, error_buf_size, "unknown type"); @@ -12459,8 +12478,8 @@ re_scan: break; } - /* table.get x. tables[x]. [i32] -> [t] */ - /* table.set x. tables[x]. [i32 t] -> [] */ + /* table.get x. tables[x]. [it] -> [t] */ + /* table.set x. tables[x]. [it t] -> [] */ case WASM_OP_TABLE_GET: case WASM_OP_TABLE_SET: { @@ -12491,8 +12510,13 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (opcode == WASM_OP_TABLE_GET) { - POP_I32(); + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_FAST_INTERP != 0 PUSH_OFFSET_TYPE(decl_ref_type); #endif @@ -12503,7 +12527,7 @@ re_scan: POP_OFFSET_TYPE(decl_ref_type); #endif POP_TYPE(decl_ref_type); - POP_I32(); + POP_TBL_ELEM_IDX(); } #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -14786,7 +14810,12 @@ re_scan: #endif POP_I32(); POP_I32(); - POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_WAMR_COMPILER != 0 module->is_ref_types_used = true; @@ -14811,7 +14840,8 @@ re_scan: } case WASM_OP_TABLE_COPY: { - uint8 src_type, dst_type; + uint8 src_type, dst_type, src_tbl_idx_type, + dst_tbl_idx_type, min_tbl_idx_type; #if WASM_ENABLE_GC != 0 WASMRefType *src_ref_type = NULL, *dst_ref_type = NULL; #endif @@ -14857,9 +14887,31 @@ re_scan: emit_uint32(loader_ctx, dst_tbl_idx); emit_uint32(loader_ctx, src_tbl_idx); #endif - POP_I32(); - POP_I32(); - POP_I32(); + +#if WASM_ENABLE_MEMORY64 != 0 + src_tbl_idx_type = is_table_64bit(module, src_tbl_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; + dst_tbl_idx_type = is_table_64bit(module, dst_tbl_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; + min_tbl_idx_type = + (src_tbl_idx_type == VALUE_TYPE_I32 + || dst_tbl_idx_type == VALUE_TYPE_I32) + ? VALUE_TYPE_I32 + : VALUE_TYPE_I64; +#else + src_tbl_idx_type = VALUE_TYPE_I32; + dst_tbl_idx_type = VALUE_TYPE_I32; + min_tbl_idx_type = VALUE_TYPE_I32; +#endif + + table_elem_idx_type = min_tbl_idx_type; + POP_TBL_ELEM_IDX(); + table_elem_idx_type = src_tbl_idx_type; + POP_TBL_ELEM_IDX(); + table_elem_idx_type = dst_tbl_idx_type; + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_WAMR_COMPILER != 0 module->is_ref_types_used = true; @@ -14879,7 +14931,12 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif - PUSH_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + PUSH_TBL_ELEM_IDX(); #if WASM_ENABLE_WAMR_COMPILER != 0 module->is_ref_types_used = true; @@ -14928,15 +14985,20 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif - POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_FAST_INTERP != 0 POP_OFFSET_TYPE(decl_type); #endif POP_TYPE(decl_type); if (opcode1 == WASM_OP_TABLE_GROW) - PUSH_I32(); + PUSH_TBL_ELEM_IDX(); else - POP_I32(); + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_WAMR_COMPILER != 0 module->is_ref_types_used = true; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 8826f98db..0d1f83704 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -33,12 +33,25 @@ has_module_memory64(WASMModule *module) /* TODO: multi-memories for now assuming the memory idx type is consistent * across multi-memories */ if (module->import_memory_count > 0) - return !!(module->import_memories[0].u.mem_type.flags & MEMORY64_FLAG); + return !!(module->import_memories[0].u.memory.mem_type.flags + & MEMORY64_FLAG); else if (module->memory_count > 0) return !!(module->memories[0].flags & MEMORY64_FLAG); return false; } + +static bool +is_table_64bit(WASMModule *module, uint32 table_idx) +{ + if (table_idx < module->import_table_count) + return !!(module->import_tables[table_idx].u.table.table_type.flags + & TABLE64_FLAG); + else + return !!(module->tables[table_idx].table_type.flags & TABLE64_FLAG); + + return false; +} #endif static void @@ -577,11 +590,15 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } static void -adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size) +adjust_table_max_size(bool is_table64, uint32 init_size, uint32 max_size_flag, + uint32 *max_size) { uint32 default_max_size = init_size * 2 > WASM_TABLE_MAX_SIZE ? init_size * 2 : WASM_TABLE_MAX_SIZE; + /* TODO: current still use UINT32_MAX as upper limit for table size to keep + * ABI unchanged */ + (void)is_table64; if (max_size_flag) { /* module defines the table limitation */ @@ -642,8 +659,8 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; - uint32 declare_elem_type = 0, declare_max_size_flag = 0, - declare_init_size = 0, declare_max_size = 0; + uint32 declare_elem_type = 0, table_flag = 0, declare_init_size = 0, + declare_max_size = 0; CHECK_BUF(p, p_end, 1); /* 0x70 or 0x6F */ @@ -654,24 +671,29 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, #endif ); - read_leb_uint32(p, p_end, declare_max_size_flag); + read_leb_uint32(p, p_end, table_flag); + + if (!wasm_table_check_flags(table_flag, error_buf, error_buf_size, false)) { + return false; + } + read_leb_uint32(p, p_end, declare_init_size); - if (declare_max_size_flag & 1) { + if (table_flag & MAX_TABLE_SIZE_FLAG) { read_leb_uint32(p, p_end, declare_max_size); bh_assert(table->table_type.init_size <= table->table_type.max_size); } - adjust_table_max_size(declare_init_size, declare_max_size_flag, - &declare_max_size); + adjust_table_max_size(table_flag & TABLE64_FLAG, declare_init_size, + table_flag & MAX_TABLE_SIZE_FLAG, &declare_max_size); *p_buf = p; - bh_assert( - !((declare_max_size_flag & 1) && declare_init_size > declare_max_size)); + bh_assert(!((table_flag & MAX_TABLE_SIZE_FLAG) + && declare_init_size > declare_max_size)); /* now we believe all declaration are ok */ table->table_type.elem_type = declare_elem_type; table->table_type.init_size = declare_init_size; - table->table_type.flags = declare_max_size_flag; + table->table_type.flags = table_flag; table->table_type.max_size = declare_max_size; return true; } @@ -789,16 +811,22 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, p_org = p; read_leb_uint32(p, p_end, table->table_type.flags); bh_assert(p - p_org <= 1); - bh_assert(table->table_type.flags <= 1); (void)p_org; + if (!wasm_table_check_flags(table->table_type.flags, error_buf, + error_buf_size, false)) { + return false; + } + read_leb_uint32(p, p_end, table->table_type.init_size); - if (table->table_type.flags == 1) { + if (table->table_type.flags == MAX_TABLE_SIZE_FLAG) { read_leb_uint32(p, p_end, table->table_type.max_size); bh_assert(table->table_type.init_size <= table->table_type.max_size); } - adjust_table_max_size(table->table_type.init_size, table->table_type.flags, + adjust_table_max_size(table->table_type.flags & TABLE64_FLAG, + table->table_type.init_size, + table->table_type.flags & MAX_TABLE_SIZE_FLAG, &table->table_type.max_size); *p_buf = p; @@ -1575,6 +1603,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; + uint8 table_elem_idx_type; uint32 table_segment_count, i, table_index, function_count; uint64 total_size; WASMTableSeg *table_segment; @@ -1592,6 +1621,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, table_segment = module->table_segments; for (i = 0; i < table_segment_count; i++, table_segment++) { bh_assert(p < p_end); + table_elem_idx_type = VALUE_TYPE_I32; #if WASM_ENABLE_REF_TYPES != 0 read_leb_uint32(p, p_end, table_segment->mode); @@ -1608,9 +1638,15 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (!load_init_expr( module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, error_buf, error_buf_size)) + table_elem_idx_type, error_buf, error_buf_size)) return false; if (table_segment->mode == 0) { @@ -1646,9 +1682,15 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, &table_segment->table_index, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (!load_init_expr( module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, error_buf, error_buf_size)) + table_elem_idx_type, error_buf, error_buf_size)) return false; if (!load_elem_type(&p, p_end, &table_segment->elem_type, table_segment->mode == 2 ? true : false, @@ -1691,13 +1733,29 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, &table_segment->table_index, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (!load_init_expr(module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, error_buf, error_buf_size)) + table_elem_idx_type, error_buf, error_buf_size)) return false; if (!load_func_index_vec(&p, p_end, module, table_segment, error_buf, error_buf_size)) return false; #endif /* WASM_ENABLE_REF_TYPES != 0 */ + +#if WASM_ENABLE_MEMORY64 != 0 + if (table_elem_idx_type == VALUE_TYPE_I64 + && table_segment->base_offset.u.u64 > UINT32_MAX) { + set_error_buf(error_buf, error_buf_size, + "In table64, table base offset can't be " + "larger than UINT32_MAX"); + return false; + } +#endif } } @@ -1781,8 +1839,8 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, /* This memory_flag is from memory instead of data segment */ uint8 memory_flag; if (module->import_memory_count > 0) { - memory_flag = - module->import_memories[mem_index].u.mem_type.flags; + memory_flag = module->import_memories[mem_index] + .u.memory.mem_type.flags; } else { memory_flag = @@ -2148,7 +2206,8 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, option.enable_aux_stack_check = true; #if WASM_ENABLE_PERF_PROFILING != 0 || WASM_ENABLE_DUMP_CALL_STACK != 0 \ || WASM_ENABLE_AOT_STACK_FRAME != 0 - option.enable_aux_stack_frame = true; + option.aux_stack_frame_type = AOT_STACK_FRAME_TYPE_STANDARD; + aot_call_stack_features_init_default(&option.call_stack_features); #endif #if WASM_ENABLE_PERF_PROFILING != 0 option.enable_perf_profiling = true; @@ -2157,6 +2216,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, option.enable_memory_profiling = true; option.enable_stack_estimation = true; #endif +#if WASM_ENABLE_SHARED_HEAP != 0 + option.enable_shared_heap = true; +#endif module->comp_ctx = aot_create_comp_context(module->comp_data, &option); if (!module->comp_ctx) { @@ -2531,7 +2593,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, #if WASM_ENABLE_FAST_INTERP != 0 && WASM_ENABLE_LABELS_AS_VALUES != 0 void ** -wasm_interp_get_handle_table(); +wasm_interp_get_handle_table(void); static void **handle_table; #endif @@ -2947,6 +3009,12 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } +#if WASM_ENABLE_MEMORY64 != 0 + if (!check_memory64_flags_consistency(module, error_buf, error_buf_size, + false)) + return false; +#endif + calculate_global_data_offset(module); #if WASM_ENABLE_FAST_JIT != 0 @@ -5213,6 +5281,13 @@ fail: } while (0) #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() +#define PUSH_TBL_ELEM_IDX() \ + do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, table_elem_idx_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_MEM_OFFSET() \ do { \ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, mem_offset_type, \ @@ -5220,6 +5295,13 @@ fail: goto fail; \ } while (0) +#define POP_TBL_ELEM_IDX() \ + do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, table_elem_idx_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_AND_PUSH(type_pop, type_push) \ do { \ if (!(wasm_loader_push_pop_frame_ref_offset( \ @@ -5283,6 +5365,13 @@ fail: #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() +#define PUSH_TBL_ELEM_IDX() \ + do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, table_elem_idx_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_I32() \ do { \ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, error_buf, \ @@ -5325,6 +5414,13 @@ fail: goto fail; \ } while (0) +#define POP_TBL_ELEM_IDX() \ + do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, table_elem_idx_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_AND_PUSH(type_pop, type_push) \ do { \ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, type_push, \ @@ -5944,7 +6040,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; - uint8 *param_types, *local_types, local_type, global_type, mem_offset_type; + uint8 *param_types, *local_types, local_type, global_type, mem_offset_type, + table_elem_idx_type; BlockType func_block_type; uint16 *local_offsets, local_offset; uint32 count, local_idx, global_idx, u32, align, i, memidx; @@ -5975,6 +6072,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32; #else mem_offset_type = VALUE_TYPE_I32; + table_elem_idx_type = VALUE_TYPE_I32; #endif global_count = module->import_global_count + module->global_count; @@ -6587,8 +6685,13 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif /* skip elem idx */ - POP_I32(); + POP_TBL_ELEM_IDX(); bh_assert(type_idx < module->type_count); @@ -6864,8 +6967,8 @@ re_scan: break; } - /* table.get x. tables[x]. [i32] -> [t] */ - /* table.set x. tables[x]. [i32 t] -> [] */ + /* table.get x. tables[x]. [it] -> [t] */ + /* table.set x. tables[x]. [it t] -> [] */ case WASM_OP_TABLE_GET: case WASM_OP_TABLE_SET: { @@ -6881,8 +6984,13 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (opcode == WASM_OP_TABLE_GET) { - POP_I32(); + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_FAST_INTERP != 0 PUSH_OFFSET_TYPE(decl_ref_type); #endif @@ -6893,7 +7001,7 @@ re_scan: POP_OFFSET_TYPE(decl_ref_type); #endif POP_TYPE(decl_ref_type); - POP_I32(); + POP_TBL_ELEM_IDX(); } break; } @@ -7818,7 +7926,12 @@ re_scan: #endif POP_I32(); POP_I32(); - POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + POP_TBL_ELEM_IDX(); break; } case WASM_OP_ELEM_DROP: @@ -7837,7 +7950,8 @@ re_scan: case WASM_OP_TABLE_COPY: { uint8 src_ref_type, dst_ref_type; - uint32 src_tbl_idx, dst_tbl_idx; + uint32 src_tbl_idx, dst_tbl_idx, src_tbl_idx_type, + dst_tbl_idx_type, min_tbl_idx_type; read_leb_uint32(p, p_end, src_tbl_idx); if (!get_table_elem_type(module, src_tbl_idx, @@ -7861,9 +7975,31 @@ re_scan: emit_uint32(loader_ctx, src_tbl_idx); emit_uint32(loader_ctx, dst_tbl_idx); #endif - POP_I32(); - POP_I32(); - POP_I32(); + +#if WASM_ENABLE_MEMORY64 != 0 + src_tbl_idx_type = is_table_64bit(module, src_tbl_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; + dst_tbl_idx_type = is_table_64bit(module, dst_tbl_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; + min_tbl_idx_type = + (src_tbl_idx_type == VALUE_TYPE_I32 + || dst_tbl_idx_type == VALUE_TYPE_I32) + ? VALUE_TYPE_I32 + : VALUE_TYPE_I64; +#else + src_tbl_idx_type = VALUE_TYPE_I32; + dst_tbl_idx_type = VALUE_TYPE_I32; + min_tbl_idx_type = VALUE_TYPE_I32; +#endif + + table_elem_idx_type = min_tbl_idx_type; + POP_TBL_ELEM_IDX(); + table_elem_idx_type = src_tbl_idx_type; + POP_TBL_ELEM_IDX(); + table_elem_idx_type = dst_tbl_idx_type; + POP_TBL_ELEM_IDX(); break; } case WASM_OP_TABLE_SIZE: @@ -7881,7 +8017,12 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif - PUSH_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + PUSH_TBL_ELEM_IDX(); break; } case WASM_OP_TABLE_GROW: @@ -7913,15 +8054,20 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif - POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_FAST_INTERP != 0 POP_OFFSET_TYPE(decl_ref_type); #endif POP_TYPE(decl_ref_type); if (opcode1 == WASM_OP_TABLE_GROW) - PUSH_I32(); + PUSH_TBL_ELEM_IDX(); else - POP_I32(); + PUSH_TBL_ELEM_IDX(); break; } #endif /* WASM_ENABLE_REF_TYPES */ diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f70f9cb73..accb40319 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -83,6 +83,124 @@ wasm_unload(WASMModule *module) wasm_loader_unload(module); } +bool +wasm_resolve_symbols(WASMModule *module) +{ + bool ret = true; + uint32 idx; + for (idx = 0; idx < module->import_function_count; ++idx) { + WASMFunctionImport *import = &module->import_functions[idx].u.function; + bool linked = import->func_ptr_linked; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (import->import_func_linked) { + linked = true; + } +#endif + if (!linked && !wasm_resolve_import_func(module, import)) { + ret = false; + } + } + return ret; +} + +#if WASM_ENABLE_MULTI_MODULE != 0 +static WASMFunction * +wasm_resolve_function(const char *module_name, const char *function_name, + const WASMFuncType *expected_function_type, + char *error_buf, uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + WASMFunction *function = NULL; + WASMExport *export = NULL; + WASMModule *module = NULL; + WASMFuncType *target_function_type = NULL; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { + LOG_DEBUG("can not find a module named %s for function %s", module_name, + function_name); + set_error_buf(error_buf, error_buf_size, "unknown import"); + return NULL; + } + + module = (WASMModule *)module_reg; + export = loader_find_export((WASMModuleCommon *)module, module_name, + function_name, EXPORT_KIND_FUNC, error_buf, + error_buf_size); + if (!export) { + return NULL; + } + + /* resolve function type and function */ + if (export->index < module->import_function_count) { + target_function_type = + module->import_functions[export->index].u.function.func_type; + function = module->import_functions[export->index] + .u.function.import_func_linked; + } + else { + target_function_type = + module->functions[export->index - module->import_function_count] + ->func_type; + function = + module->functions[export->index - module->import_function_count]; + } + + /* check function type */ + if (!wasm_type_equal((WASMType *)expected_function_type, + (WASMType *)target_function_type, module->types, + module->type_count)) { + LOG_DEBUG("%s.%s failed the type check", module_name, function_name); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + + return function; +} +#endif + +bool +wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function) +{ +#if WASM_ENABLE_MULTI_MODULE != 0 + char error_buf[128]; + WASMModule *sub_module = NULL; +#endif + function->func_ptr_linked = wasm_native_resolve_symbol( + function->module_name, function->field_name, function->func_type, + &function->signature, &function->attachment, &function->call_conv_raw); + + if (function->func_ptr_linked) { + return true; + } + +#if WASM_ENABLE_MULTI_MODULE != 0 + if (!wasm_runtime_is_built_in_module(function->module_name)) { + sub_module = (WASMModule *)wasm_runtime_load_depended_module( + (WASMModuleCommon *)module, function->module_name, error_buf, + sizeof(error_buf)); + if (!sub_module) { + LOG_WARNING("failed to load sub module: %s", error_buf); + return false; + } + } + function->import_func_linked = wasm_resolve_function( + function->module_name, function->field_name, function->func_type, + error_buf, sizeof(error_buf)); + + if (function->import_func_linked) { + function->import_module = sub_module; + return true; + } + else { + LOG_WARNING("failed to link function (%s, %s): %s", + function->module_name, function->field_name, error_buf); + } +#endif + + return false; +} + static void * runtime_malloc(uint64 size, char *error_buf, uint32 error_buf_size) { @@ -560,6 +678,8 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, uninitialized elements */ #endif + table->is_table64 = import->u.table.table_type.flags & TABLE64_FLAG; + #if WASM_ENABLE_MULTI_MODULE != 0 *table_linked = table_inst_linked; if (table_inst_linked != NULL) { @@ -618,6 +738,7 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, /* For GC, all elements have already been set to NULL_REF (0) as uninitialized elements */ #endif + table->is_table64 = module->tables[i].table_type.flags & TABLE64_FLAG; table->elem_type = module->tables[i].table_type.elem_type; #if WASM_ENABLE_GC != 0 table->elem_ref_type.elem_ref_type = @@ -1246,6 +1367,17 @@ export_functions_deinstantiate(WASMExportFuncInstance *functions) wasm_runtime_free(functions); } +static int +cmp_export_func_inst(const void *a, const void *b) +{ + const WASMExportFuncInstance *export_func1 = + (const WASMExportFuncInstance *)a; + const WASMExportFuncInstance *export_func2 = + (const WASMExportFuncInstance *)b; + + return strcmp(export_func1->name, export_func2->name); +} + /** * Instantiate export functions in a module. */ @@ -1274,6 +1406,9 @@ export_functions_instantiate(const WASMModule *module, } bh_assert((uint32)(export_func - export_funcs) == export_func_count); + + qsort(export_funcs, export_func_count, sizeof(WASMExportFuncInstance), + cmp_export_func_inst); return export_funcs; } @@ -1323,42 +1458,6 @@ export_tags_instantiate(const WASMModule *module, } #endif /* end of WASM_ENABLE_TAGS != 0 */ -#if WASM_ENABLE_MULTI_MODULE != 0 -static void -export_globals_deinstantiate(WASMExportGlobInstance *globals) -{ - if (globals) - wasm_runtime_free(globals); -} - -static WASMExportGlobInstance * -export_globals_instantiate(const WASMModule *module, - WASMModuleInstance *module_inst, - uint32 export_glob_count, char *error_buf, - uint32 error_buf_size) -{ - WASMExportGlobInstance *export_globals, *export_global; - WASMExport *export = module->exports; - uint32 i; - uint64 total_size = - sizeof(WASMExportGlobInstance) * (uint64)export_glob_count; - - if (!(export_global = export_globals = - runtime_malloc(total_size, error_buf, error_buf_size))) { - return NULL; - } - - for (i = 0; i < module->export_count; i++, export ++) - if (export->kind == EXPORT_KIND_GLOBAL) { - export_global->name = export->name; - export_global->global = &module_inst->e->globals[export->index]; - export_global++; - } - - bh_assert((uint32)(export_global - export_globals) == export_glob_count); - return export_globals; -} - #if WASM_ENABLE_MULTI_MEMORY != 0 static void export_memories_deinstantiate(WASMExportMemInstance *memories) @@ -1396,6 +1495,42 @@ export_memories_instantiate(const WASMModule *module, } #endif /* end of if WASM_ENABLE_MULTI_MEMORY != 0 */ +#if WASM_ENABLE_MULTI_MODULE != 0 +static void +export_globals_deinstantiate(WASMExportGlobInstance *globals) +{ + if (globals) + wasm_runtime_free(globals); +} + +static WASMExportGlobInstance * +export_globals_instantiate(const WASMModule *module, + WASMModuleInstance *module_inst, + uint32 export_glob_count, char *error_buf, + uint32 error_buf_size) +{ + WASMExportGlobInstance *export_globals, *export_global; + WASMExport *export = module->exports; + uint32 i; + uint64 total_size = + sizeof(WASMExportGlobInstance) * (uint64)export_glob_count; + + if (!(export_global = export_globals = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return NULL; + } + + for (i = 0; i < module->export_count; i++, export ++) + if (export->kind == EXPORT_KIND_GLOBAL) { + export_global->name = export->name; + export_global->global = &module_inst->e->globals[export->index]; + export_global++; + } + + bh_assert((uint32)(export_global - export_globals) == export_glob_count); + return export_globals; +} + #endif /* end of if WASM_ENABLE_MULTI_MODULE != 0 */ static WASMFunctionInstance * @@ -1476,8 +1611,12 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst, if (is_sub_inst) { bh_assert(exec_env_main); #ifdef OS_ENABLE_HW_BOUND_CHECK - bh_assert(exec_env_tls == exec_env_main); - (void)exec_env_tls; + /* May come from pthread_create_wrapper, thread_spawn_wrapper and + wasm_cluster_spawn_exec_env. If it comes from the former two, + the exec_env_tls must be not NULL and equal to exec_env_main, + else if it comes from the last one, it may be NULL. */ + if (exec_env_tls) + bh_assert(exec_env_tls == exec_env_main); #endif exec_env = exec_env_main; @@ -2388,11 +2527,13 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, /* export */ module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC); +#if WASM_ENABLE_MULTI_MEMORY != 0 + module_inst->export_memory_count = + get_export_count(module, EXPORT_KIND_MEMORY); +#endif #if WASM_ENABLE_MULTI_MODULE != 0 module_inst->export_table_count = get_export_count(module, EXPORT_KIND_TABLE); - module_inst->export_memory_count = - get_export_count(module, EXPORT_KIND_MEMORY); #if WASM_ENABLE_TAGS != 0 module_inst->e->export_tag_count = get_export_count(module, EXPORT_KIND_TAG); @@ -2432,7 +2573,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, module, module_inst, module_inst->export_global_count, error_buf, error_buf_size))) #endif -#if WASM_ENABLE_MULTI_MODULE != 0 && WASM_ENABLE_MULTI_MEMORY != 0 +#if WASM_ENABLE_MULTI_MEMORY != 0 || (module_inst->export_memory_count > 0 && !(module_inst->export_memories = export_memories_instantiate( module, module_inst, module_inst->export_memory_count, @@ -2671,6 +2812,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, } } +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0 +#if UINTPTR_MAX == UINT64_MAX + module_inst->e->shared_heap_start_off.u64 = UINT64_MAX; +#else + module_inst->e->shared_heap_start_off.u32[0] = UINT32_MAX; +#endif +#endif + #if WASM_ENABLE_GC != 0 /* Initialize the table data with init expr */ for (i = 0; i < module->table_count; i++) { @@ -3240,7 +3389,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) export_globals_deinstantiate(module_inst->export_globals); #endif -#if WASM_ENABLE_MULTI_MODULE != 0 && WASM_ENABLE_MULTI_MEMORY != 0 +#if WASM_ENABLE_MULTI_MEMORY != 0 export_memories_deinstantiate(module_inst->export_memories); #endif @@ -3285,22 +3434,20 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) WASMFunctionInstance * wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name) { - uint32 i; - for (i = 0; i < module_inst->export_func_count; i++) - if (!strcmp(module_inst->export_functions[i].name, name)) - return module_inst->export_functions[i].function; - return NULL; -} + WASMExportFuncInstance key = { .name = (char *)name }; + WASMExportFuncInstance *export_func_inst; -#if WASM_ENABLE_MULTI_MODULE != 0 -WASMGlobalInstance * -wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name) -{ - uint32 i; - for (i = 0; i < module_inst->export_global_count; i++) - if (!strcmp(module_inst->export_globals[i].name, name)) - return module_inst->export_globals[i].global; - return NULL; + if (!module_inst->export_functions) + return NULL; + + export_func_inst = bsearch( + &key, module_inst->export_functions, module_inst->export_func_count, + sizeof(WASMExportFuncInstance), cmp_export_func_inst); + + if (!export_func_inst) + return NULL; + + return export_func_inst->function; } WASMMemoryInstance * @@ -3314,10 +3461,23 @@ wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name) return NULL; #else (void)module_inst->export_memories; + if (!module_inst->memories) + return NULL; return module_inst->memories[0]; #endif } +#if WASM_ENABLE_MULTI_MODULE != 0 +WASMGlobalInstance * +wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name) +{ + uint32 i; + for (i = 0; i < module_inst->export_global_count; i++) + if (!strcmp(module_inst->export_globals[i].name, name)) + return module_inst->export_globals[i].global; + return NULL; +} + WASMTableInstance * wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name) { diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 8666541f2..00e9ad107 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -92,6 +92,15 @@ typedef union { uint32 u32[2]; } MemBound; +typedef struct WASMSharedHeap { + struct WASMSharedHeap *next; + void *heap_handle; + uint8 *base_addr; + uint64 size; + uint64 start_off_mem64; + uint64 start_off_mem32; +} WASMSharedHeap; + struct WASMMemoryInstance { /* Module type */ uint32 module_type; @@ -157,7 +166,8 @@ struct WASMMemoryInstance { struct WASMTableInstance { /* The element type */ uint8 elem_type; - uint8 __padding__[7]; + uint8 is_table64; + uint8 __padding__[6]; union { #if WASM_ENABLE_GC != 0 WASMRefType *elem_ref_type; @@ -353,6 +363,19 @@ typedef struct WASMModuleInstanceExtra { uint32 max_aux_stack_used; #endif +#if WASM_ENABLE_SHARED_HEAP != 0 + WASMSharedHeap *shared_heap; +#if WASM_ENABLE_JIT != 0 + /* + * Adjusted shared heap based addr to simple the calculation + * in the aot code. The value is: + * shared_heap->base_addr - shared_heap->start_off + */ + uint8 *shared_heap_base_addr_adj; + MemBound shared_heap_start_off; +#endif +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 \ || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ && WASM_ENABLE_LAZY_JIT != 0) @@ -513,6 +536,13 @@ wasm_load_from_sections(WASMSection *section_list, char *error_buf, void wasm_unload(WASMModule *module); +bool +wasm_resolve_symbols(WASMModule *module); + +bool +wasm_resolve_import_func(const WASMModule *module, + WASMFunctionImport *function); + WASMModuleInstance * wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, WASMExecEnv *exec_env_main, uint32 stack_size, @@ -539,13 +569,13 @@ wasm_set_running_mode(WASMModuleInstance *module_inst, WASMFunctionInstance * wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name); +WASMMemoryInstance * +wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name); + #if WASM_ENABLE_MULTI_MODULE != 0 WASMGlobalInstance * wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name); -WASMMemoryInstance * -wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name); - WASMTableInstance * wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name); diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread.cmake b/core/iwasm/libraries/lib-pthread/lib_pthread.cmake index 134edf0e8..a1d183ee1 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread.cmake +++ b/core/iwasm/libraries/lib-pthread/lib_pthread.cmake @@ -6,7 +6,7 @@ set (LIB_PTHREAD_DIR ${CMAKE_CURRENT_LIST_DIR}) add_definitions (-DWASM_ENABLE_LIB_PTHREAD=1) if (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE EQUAL 1) -add_definitions (-DWASM_ENABLE_LIB_PTHREAD_SEMAPHORE=1) + add_definitions (-DWASM_ENABLE_LIB_PTHREAD_SEMAPHORE=1) endif() include_directories(${LIB_PTHREAD_DIR}) diff --git a/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c b/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c index aeaafced7..c9512fb43 100644 --- a/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c +++ b/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c @@ -29,7 +29,7 @@ typedef struct { } ThreadStartArg; static int32 -allocate_thread_id() +allocate_thread_id(void) { os_mutex_lock(&thread_id_lock); int32 id = tid_allocator_get_tid(&tid_allocator); diff --git a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c index 427bfd656..3bb6bc6b7 100644 --- a/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c +++ b/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -7,8 +7,13 @@ #include "bh_log.h" #include "wasm_export.h" #include "../interpreter/wasm.h" -#if !defined(_DEFAULT_SOURCE) && !defined(BH_PLATFORM_LINUX_SGX) -#include "sys/syscall.h" + +#if defined(__linux__) +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) +#define HAVE_SYSCALL_GETRANDOM +#include +#endif #endif /* clang-format off */ @@ -168,12 +173,21 @@ statbuf_native2app(const struct stat *statbuf_native, statbuf_app->st_blksize = (unsigned)statbuf_native->st_blksize; statbuf_app->st_blocks = (unsigned)statbuf_native->st_blocks; statbuf_app->st_ino = (int64)statbuf_native->st_ino; +#if defined(__APPLE__) + statbuf_app->st_atim.tv_sec = (int)statbuf_native->st_atimespec.tv_sec; + statbuf_app->st_atim.tv_nsec = (int)statbuf_native->st_atimespec.tv_nsec; + statbuf_app->st_mtim.tv_sec = (int)statbuf_native->st_mtimespec.tv_sec; + statbuf_app->st_mtim.tv_nsec = (int)statbuf_native->st_mtimespec.tv_nsec; + statbuf_app->st_ctim.tv_sec = (int)statbuf_native->st_ctimespec.tv_sec; + statbuf_app->st_ctim.tv_nsec = (int)statbuf_native->st_ctimespec.tv_nsec; +#else statbuf_app->st_atim.tv_sec = (int)statbuf_native->st_atim.tv_sec; statbuf_app->st_atim.tv_nsec = (int)statbuf_native->st_atim.tv_nsec; statbuf_app->st_mtim.tv_sec = (int)statbuf_native->st_mtim.tv_sec; statbuf_app->st_mtim.tv_nsec = (int)statbuf_native->st_mtim.tv_nsec; statbuf_app->st_ctim.tv_sec = (int)statbuf_native->st_ctim.tv_sec; statbuf_app->st_ctim.tv_nsec = (int)statbuf_native->st_ctim.tv_nsec; +#endif } static int @@ -261,10 +275,10 @@ getentropy_wrapper(wasm_exec_env_t exec_env, void *buffer, uint32 length) { if (buffer == NULL) return -1; -#if defined(_DEFAULT_SOURCE) || defined(BH_PLATFORM_LINUX_SGX) - return getentropy(buffer, length); -#else +#if defined(HAVE_SYSCALL_GETRANDOM) return syscall(SYS_getrandom, buffer, length, 0); +#else + return getentropy(buffer, length); #endif } diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index aef8f1703..6d057a6a1 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -1022,8 +1022,8 @@ execute_interruptible_poll_oneoff( uint32 i; const __wasi_timestamp_t timeout = get_timeout_for_poll_oneoff( - in, nsubscriptions), - time_quant = 1e9; + in, (uint32)nsubscriptions), + time_quant = (__wasi_timestamp_t)1e9; const uint64 size_to_copy = nsubscriptions * (uint64)sizeof(wasi_subscription_t); __wasi_subscription_t *in_copy = NULL; @@ -1034,12 +1034,13 @@ execute_interruptible_poll_oneoff( return __WASI_ENOMEM; } - bh_memcpy_s(in_copy, size_to_copy, in, size_to_copy); + bh_memcpy_s(in_copy, (uint32)size_to_copy, in, (uint32)size_to_copy); while (timeout == (__wasi_timestamp_t)-1 || elapsed <= timeout) { /* update timeout for clock subscription events */ update_clock_subscription_data( - in_copy, nsubscriptions, min_uint64(time_quant, timeout - elapsed)); + in_copy, (uint32)nsubscriptions, + min_uint64(time_quant, timeout - elapsed)); err = wasmtime_ssp_poll_oneoff(exec_env, curfds, in_copy, out, nsubscriptions, nevents); elapsed += time_quant; diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index a313b9be5..d26c460fe 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -3130,7 +3130,7 @@ compare_address(const struct addr_pool *addr_pool_entry, } addr_size = 16; } - max_addr_mask = addr_size * 8; + max_addr_mask = (uint8)(addr_size * 8); /* IPv4 0.0.0.0 or IPv6 :: means any address */ if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) { diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h index 03b4b87ac..79b16cc17 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h @@ -132,6 +132,35 @@ refcount_release(struct refcount *r) #error "Reference counter isn't implemented" #endif /* end of __GNUC_PREREQ (4.7) */ +#elif defined(_MSC_VER) + +/* Simple reference counter. */ +struct LOCKABLE refcount { + LONG count; +}; + +/* Initialize the reference counter. */ +static inline void +refcount_init(struct refcount *r, unsigned int count) +{ + InterlockedExchange(&r->count, (LONG)count); +} + +/* Increment the reference counter. */ +static inline void +refcount_acquire(struct refcount *r) +{ + InterlockedIncrement(&r->count); +} + +/* Decrement the reference counter, returning whether the reference + dropped to zero. */ +static inline bool +refcount_release(struct refcount *r) +{ + return InterlockedDecrement(&r->count) == 0 ? true : false; +} + #else /* else of CONFIG_HAS_STD_ATOMIC */ #error "Reference counter isn't implemented" #endif /* end of CONFIG_HAS_STD_ATOMIC */ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index 4ef29ccdb..829677213 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -70,9 +70,11 @@ #endif #if !defined(BH_PLATFORM_LINUX_SGX) + /* Clang's __GNUC_PREREQ macro has a different meaning than GCC one, so we have to handle this case specially */ #if defined(__clang__) + /* Clang provides stdatomic.h since 3.6.0 See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */ #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) @@ -80,7 +82,9 @@ See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */ #else #define CONFIG_HAS_STD_ATOMIC 0 #endif + #elif defined(__GNUC_PREREQ) + /* Even though older versions of GCC support C11, atomics were not implemented until 4.9. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */ @@ -89,11 +93,21 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */ #else /* else of __GNUC_PREREQ(4, 9) */ #define CONFIG_HAS_STD_ATOMIC 0 #endif /* end of __GNUC_PREREQ(4, 9) */ -#else /* else of defined(__GNUC_PREREQ) */ -#define CONFIG_HAS_STD_ATOMIC 1 -#endif /* end of defined(__GNUC_PREREQ) */ -#else /* else of !defined(BH_PLATFORM_LINUX_SGX) */ + +#elif defined(_MSC_VER) + #define CONFIG_HAS_STD_ATOMIC 0 + +#else + +#define CONFIG_HAS_STD_ATOMIC 1 + +#endif /* end of defined(__clang__) */ + +#else /* else of !defined(BH_PLATFORM_LINUX_SGX) */ + +#define CONFIG_HAS_STD_ATOMIC 0 + #endif /* end of !defined(BH_PLATFORM_LINUX_SGX) */ -#endif +#endif /* end of SSP_CONFIG_H */ diff --git a/core/iwasm/libraries/shared-heap/shared_heap.cmake b/core/iwasm/libraries/shared-heap/shared_heap.cmake new file mode 100644 index 000000000..ec91dabcd --- /dev/null +++ b/core/iwasm/libraries/shared-heap/shared_heap.cmake @@ -0,0 +1,8 @@ +# Copyright (C) 2024 Xiaomi Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIB_SHARED_HEAP ${CMAKE_CURRENT_LIST_DIR}) +add_definitions (-DWASM_ENABLE_SHARED_HEAP=1) +include_directories(${LIB_SHARED_HEAP_DIR}) +file (GLOB source_all ${LIB_SHARED_HEAP}/*.c) +set (LIB_SHARED_HEAP_SOURCE ${source_all}) \ No newline at end of file diff --git a/core/iwasm/libraries/shared-heap/shared_heap_wrapper.c b/core/iwasm/libraries/shared-heap/shared_heap_wrapper.c new file mode 100644 index 000000000..b7b78307a --- /dev/null +++ b/core/iwasm/libraries/shared-heap/shared_heap_wrapper.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 Xiaomi Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_common.h" +#include "bh_log.h" +#include "wasm_export.h" +#include "../interpreter/wasm.h" +#include "../common/wasm_runtime_common.h" +/* clang-format off */ +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define module_shared_malloc(size, p_native_addr) \ + wasm_runtime_shared_heap_malloc(module_inst, size, p_native_addr) + +#define module_shared_free(offset) \ + wasm_runtime_shared_heap_free(module_inst, offset) +/* clang-format on */ + +static uint32 +shared_heap_malloc_wrapper(wasm_exec_env_t exec_env, uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + return (uint32)module_shared_malloc((uint64)size, NULL); +} + +static void +shared_heap_free_wrapper(wasm_exec_env_t exec_env, void *ptr) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + if (!validate_native_addr(ptr, (uint64)sizeof(uintptr_t))) { + LOG_WARNING("Invalid app address"); + return; + } + + module_shared_free(addr_native_to_app(ptr)); +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_shared_heap[] = { + REG_NATIVE_FUNC(shared_heap_malloc, "(i)i"), + REG_NATIVE_FUNC(shared_heap_free, "(*)"), +}; + +uint32 +get_lib_shared_heap_export_apis(NativeSymbol **p_shared_heap_apis) +{ + *p_shared_heap_apis = native_symbols_shared_heap; + return sizeof(native_symbols_shared_heap) / sizeof(NativeSymbol); +} diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index ebb56ba7c..55e0526c3 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -1402,6 +1402,82 @@ wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, } } +#if WASM_ENABLE_SHARED_HEAP != 0 +static void +attach_shared_heap_visitor(void *node, void *heap) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env); + + wasm_runtime_attach_shared_heap_internal(module_inst, heap); +} + +static void +detach_shared_heap_visitor(void *node, void *heap) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env); + + (void)heap; + wasm_runtime_detach_shared_heap_internal(module_inst); +} + +bool +wasm_cluster_attach_shared_heap(WASMModuleInstanceCommon *module_inst, + WASMSharedHeap *heap) +{ + WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst); + + if (exec_env == NULL) { + /* Maybe threads have not been started yet. */ + return wasm_runtime_attach_shared_heap_internal(module_inst, heap); + } + else { + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + os_mutex_lock(&cluster->lock); + /* Try attaching shared heap to this module instance first + to ensure that we can attach it to all other instances. */ + if (!wasm_runtime_attach_shared_heap_internal(module_inst, heap)) { + os_mutex_unlock(&cluster->lock); + return false; + } + /* Detach the shared heap so it can be attached again. */ + wasm_runtime_detach_shared_heap_internal(module_inst); + traverse_list(&cluster->exec_env_list, attach_shared_heap_visitor, + heap); + os_mutex_unlock(&cluster->lock); + } + + return true; +} + +void +wasm_cluster_detach_shared_heap(WASMModuleInstanceCommon *module_inst) +{ + WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst); + + if (exec_env == NULL) { + /* Maybe threads have not been started yet. */ + wasm_runtime_detach_shared_heap_internal(module_inst); + } + else { + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + os_mutex_lock(&cluster->lock); + traverse_list(&cluster->exec_env_list, detach_shared_heap_visitor, + NULL); + os_mutex_unlock(&cluster->lock); + } +} +#endif + #if WASM_ENABLE_MODULE_INST_CONTEXT != 0 struct inst_set_context_data { void *key; diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index f5ca1eaed..90d97b0be 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -11,6 +11,9 @@ #include "wasm_export.h" #include "../interpreter/wasm.h" #include "../common/wasm_runtime_common.h" +#if WASM_ENABLE_SHARED_HEAP != 0 +#include "../common/wasm_memory.h" +#endif #ifdef __cplusplus extern "C" { @@ -64,10 +67,10 @@ void wasm_cluster_set_max_thread_num(uint32 num); bool -thread_manager_init(); +thread_manager_init(void); void -thread_manager_destroy(); +thread_manager_destroy(void); /* Create cluster */ WASMCluster * @@ -109,7 +112,7 @@ bool wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *)); void -wasm_cluster_cancel_all_callbacks(); +wasm_cluster_cancel_all_callbacks(void); void wasm_cluster_suspend_all(WASMCluster *cluster); @@ -167,6 +170,15 @@ wasm_cluster_set_context(WASMModuleInstanceCommon *module_inst, void *key, bool wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env); +#if WASM_ENABLE_SHARED_HEAP != 0 +bool +wasm_cluster_attach_shared_heap(WASMModuleInstanceCommon *module_inst, + WASMSharedHeap *heap); + +void +wasm_cluster_detach_shared_heap(WASMModuleInstanceCommon *module_inst); +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 #define WAMR_SIG_TRAP (5) #define WAMR_SIG_STOP (19) @@ -190,7 +202,7 @@ struct WASMCurrentEnvStatus { }; WASMCurrentEnvStatus * -wasm_cluster_create_exenv_status(); +wasm_cluster_create_exenv_status(void); void wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status); diff --git a/core/iwasm/libraries/wasi-nn/README.md b/core/iwasm/libraries/wasi-nn/README.md index e0d3a25ce..99a766467 100644 --- a/core/iwasm/libraries/wasi-nn/README.md +++ b/core/iwasm/libraries/wasi-nn/README.md @@ -4,7 +4,7 @@ ### Host -Enable WASI-NN in the WAMR by spefiying it in the cmake building configuration as follows, +Enable WASI-NN in the WAMR by specifying it in the cmake building configuration as follows, ```cmake set (WAMR_BUILD_WASI_NN 1) @@ -17,14 +17,15 @@ $ cmake -DWAMR_BUILD_WASI_NN=1 ... ``` > ![Caution] -> If enable `WAMR_BUID_WASI_NN`, iwasm will link a shared WAMR library instead of a static one. Wasi-nn backends will be loaded dynamically at runtime. Users shall specify the path of the backend library and register it to the iwasm runtime with `--native-lib=`. All shared libraries should be placed in the `LD_LIBRARY_PATH`. +> Enabling WAMR_BUILD_WASI_NN will cause the IWASM to link to a shared WAMR library instead of a static one. The WASI-NN backends will then be loaded dynamically when the program is run. You must ensure that all shared libraries are included in the `LD_LIBRARY_PATH`. #### Compilation options -- `WAMR_BUILD_WASI_NN`. enable wasi-nn support. can't work alone. need to identify a backend. Match legacy wasi-nn spec naming convention. use `wasi_nn` as import module names. -- `WAMR_BUILD_WASI_EPHEMERAL_NN`. Match latest wasi-nn spec naming convention. use `wasi_ephemeral_nn` as import module names. -- `WAMR_BUILD_WASI_NN_TFLITE`. identify the backend as TensorFlow Lite. -- `WAMR_BUILD_WASI_NN_OPENVINO`. identify the backend as OpenVINO. +- `WAMR_BUILD_WASI_NN`. This option enables support for WASI-NN. It cannot function independently and requires specifying a backend. It follows the original WASI-NN specification for naming conventions and uses wasi_nn for import module names. +- `WAMR_BUILD_WASI_EPHEMERAL_NN`. This option adheres to the most recent WASI-NN specification for naming conventions and uses wasi_ephemeral_nn for import module names. +- `WAMR_BUILD_WASI_NN_TFLITE`. This option designates TensorFlow Lite as the backend. +- `WAMR_BUILD_WASI_NN_OPENVINO`. This option designates OpenVINO as the backend. +- `WAMR_BUILD_WASI_NN_LLAMACPP`. This option designates Llama.cpp as the backend. ### Wasm @@ -44,7 +45,7 @@ typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type; It is required to recompile the Wasm application if you want to switch between the two sets of functions. -#### Openvino +#### Openvino installation If you're planning to use OpenVINO backends, the first step is to install OpenVINO on your computer. To do this correctly, please follow the official installation guide which you can find at this link: https://docs.openvino.ai/2024/get-started/install-openvino/install-openvino-archive-linux.html. @@ -102,7 +103,6 @@ docker run \ wasi-nn-cpu \ --dir=/ \ --env="TARGET=cpu" \ - --native-lib=/lib/libwasi-nn-tflite.so \ /assets/test_tensorflow.wasm ``` @@ -118,7 +118,6 @@ docker run \ wasi-nn-nvidia-gpu \ --dir=/ \ --env="TARGET=gpu" \ - --native-lib=/lib/libwasi-nn-tflite.so \ /assets/test_tensorflow.wasm ``` @@ -130,7 +129,6 @@ docker run \ wasi-nn-vx-delegate \ --dir=/ \ --env="TARGET=gpu" \ - --native-lib=/lib/libwasi-nn-tflite.so \ /assets/test_tensorflow_quantized.wasm ``` @@ -146,7 +144,6 @@ docker run \ wasi-nn-tpu \ --dir=/ \ --env="TARGET=tpu" \ - --native-lib=/lib/libwasi-nn-tflite.so \ /assets/test_tensorflow_quantized.wasm ``` @@ -154,25 +151,17 @@ docker run \ Supported: -- Graph encoding: `tensorflowlite`. -- Execution target: `cpu`, `gpu` and `tpu`. +- Graph encoding: `tensorflowlite`, `openvino` and `ggml` +- Execution target: `cpu` for all. `gpu` and `tpu` for `tensorflowlite`. - Tensor type: `fp32`. ## Smoke test ### Testing with WasmEdge-WASINN Examples -To ensure everything is set up correctly, use the examples from [WasmEdge-WASINN-examples](https://github.com/second-state/WasmEdge-WASINN-examples/tree/master). These examples help verify that WASI-NN support in WAMR is functioning as expected. +To make sure everything is configured properly, refer to the examples provided at [WasmEdge-WASINN-examples](https://github.com/second-state/WasmEdge-WASINN-examples/tree/master). These examples are useful for confirming that the WASI-NN support in WAMR is working correctly. -> Note: The repository contains two types of examples. Some use the [standard wasi-nn](https://github.com/WebAssembly/wasi-nn), while others use [WasmEdge's version of wasi-nn](https://github.com/second-state/wasmedge-wasi-nn), which is enhanced to meet specific customer needs. - -The examples test the following machine learning backends: - -- OpenVINO -- PyTorch -- TensorFlow Lite - -Due to the different requirements of each backend, we'll use a Docker container for a hassle-free testing environment. +Because each backend has its own set of requirements, we recommend using a Docker container to create a straightforward testing environment without complications. #### Prepare the execution environment @@ -186,9 +175,20 @@ $ docker build -t wasi-nn-smoke:v1.0 -f ./core/iwasm/libraries/wasi-nn/test/Dock #### Execute ```bash +$ pwd +/workspaces/wasm-micro-runtime/ $ docker run --rm wasi-nn-smoke:v1.0 ``` -### Testing with bytecodealliance wasi-nn +It should be noted that the qwen example is selected as the default one about the Llama.cpp backend because it uses a small model and is easy to run. + +```bash +- openvino_mobile_image. PASS +- openvino_mobile_raw. PASS +- openvino_road_segmentation_adas. PASS +- wasmedge_ggml_qwen. PASS +``` + +### Testing with bytecodealliance WASI-NN For another example, check out [classification-example](https://github.com/bytecodealliance/wasi-nn/tree/main/rust/examples/classification-example), which focuses on OpenVINO. You can run it using the same Docker container mentioned above. diff --git a/core/iwasm/libraries/wasi-nn/cmake/Findcjson.cmake b/core/iwasm/libraries/wasi-nn/cmake/Findcjson.cmake new file mode 100644 index 000000000..6c921bbc9 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/cmake/Findcjson.cmake @@ -0,0 +1,25 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(FetchContent) + +set(CJSON_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/cjson") +if(EXISTS ${CJSON_SOURCE_DIR}) + message("Use existed source code under ${CJSON_SOURCE_DIR}") + FetchContent_Declare( + cjson + SOURCE_DIR ${CJSON_SOURCE_DIR} + ) +else() + message("download source code and store it at ${CJSON_SOURCE_DIR}") + FetchContent_Declare( + cjson + GIT_REPOSITORY https://github.com/DaveGamble/cJSON.git + GIT_TAG v1.7.18 + SOURCE_DIR ${CJSON_SOURCE_DIR} + ) +endif() + +set(ENABLE_CJSON_TEST OFF CACHE INTERNAL "Turn off tests") +set(ENABLE_CJSON_UNINSTALL OFF CACHE INTERNAL "Turn off uninstall to avoid targets conflict") +FetchContent_MakeAvailable(cjson) diff --git a/core/iwasm/libraries/wasi-nn/cmake/Findllamacpp.cmake b/core/iwasm/libraries/wasi-nn/cmake/Findllamacpp.cmake new file mode 100644 index 000000000..8f4f8d1aa --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/cmake/Findllamacpp.cmake @@ -0,0 +1,26 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(FetchContent) + +set(LLAMA_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/llama.cpp") +if(EXISTS ${LLAMA_SOURCE_DIR}) + message("Use existed source code under ${LLAMA_SOURCE_DIR}") + FetchContent_Declare( + llamacpp + SOURCE_DIR ${LLAMA_SOURCE_DIR} + ) +else() + message("download source code and store it at ${LLAMA_SOURCE_DIR}") + FetchContent_Declare( + llamacpp + GIT_REPOSITORY https://github.com/ggerganov/llama.cpp.git + GIT_TAG b3573 + SOURCE_DIR ${LLAMA_SOURCE_DIR} + ) +endif() + +set(LLAMA_BUILD_TESTS OFF) +set(LLAMA_BUILD_EXAMPLES OFF) +set(LLAMA_BUILD_SERVER OFF) +FetchContent_MakeAvailable(llamacpp) diff --git a/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake b/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake index 052dd9804..d2b3f74e0 100644 --- a/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake +++ b/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake @@ -1,47 +1,37 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -find_library(TENSORFLOW_LITE - NAMES tensorflow-lite - HINTS ${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite - NO_DEFAULT_PATHS -) +include(FetchContent) -if(NOT TENSORFLOW_LITE) - if(NOT EXISTS "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") - execute_process( - COMMAND "${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh" - RESULT_VARIABLE TENSORFLOW_RESULT - ) - else() - message("Tensorflow is already downloaded.") - endif() - - set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") - - if(WAMR_BUILD_WASI_NN_ENABLE_GPU EQUAL 1) - # Tensorflow specific: - # * https://www.tensorflow.org/lite/guide/build_cmake#available_options_to_build_tensorflow_lite - set (TFLITE_ENABLE_GPU ON) - endif() - - if (CMAKE_SIZEOF_VOID_P EQUAL 4) - set (TFLITE_ENABLE_XNNPACK OFF) - endif() - - add_subdirectory( - "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite" - "${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite" - EXCLUDE_FROM_ALL +set(TFLITE_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") +if(EXISTS ${TFLITE_SOURCE_DIR}) + message("Use existed source code under ${TFLITE_SOURCE_DIR}") + FetchContent_Declare( + tensorflow_lite + SOURCE_DIR ${TFLITE_SOURCE_DIR} + SOURCE_SUBDIR tensorflow/lite + ) +else() + message("download source code and store it at ${TFLITE_SOURCE_DIR}") + FetchContent_Declare( + tensorflow_lite + GIT_REPOSITORY https://github.com/tensorflow/tensorflow.git + GIT_TAG v2.12.0 + GIT_SHALLOW ON + GIT_PROGRESS ON + SOURCE_DIR ${TFLITE_SOURCE_DIR} + SOURCE_SUBDIR tensorflow/lite + PATCH_COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/add_telemetry.patch ) -else () - message(STATUS "TensorFlow Lite library found: ${TENSORFLOW_LITE}") - set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") endif() -set(TENSORFLOW_LITE_INCLUDE_DIR "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite") -set(FLATBUFFER_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include") -include_directories(${TENSORFLOW_SOURCE_DIR}) -include_directories(${FLATBUFFER_INCLUDE_DIR}) -link_directories(${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite) +if(WAMR_BUILD_WASI_NN_ENABLE_GPU EQUAL 1) + set(TFLITE_ENABLE_GPU ON) +endif() + +if (CMAKE_SIZEOF_VOID_P EQUAL 4) + set(TFLITE_ENABLE_XNNPACK OFF) +endif() + +FetchContent_MakeAvailable(tensorflow_lite) diff --git a/core/iwasm/libraries/wasi-nn/cmake/add_telemetry.patch b/core/iwasm/libraries/wasi-nn/cmake/add_telemetry.patch new file mode 100644 index 000000000..8dbf5c355 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/cmake/add_telemetry.patch @@ -0,0 +1,12 @@ +diff --git a/tensorflow/lite/CMakeLists.txt b/tensorflow/lite/CMakeLists.txt +index c71a3925ac..39591a3bd7 100644 +--- a/tensorflow/lite/CMakeLists.txt ++++ b/tensorflow/lite/CMakeLists.txt +@@ -493,6 +493,7 @@ set(TFLITE_PROFILER_SRCS + ${TFLITE_SOURCE_DIR}/profiling/root_profiler.h + ${TFLITE_SOURCE_DIR}/profiling/root_profiler.cc + ${TFLITE_SOURCE_DIR}/profiling/telemetry/profiler.cc ++ ${TFLITE_SOURCE_DIR}/profiling/telemetry/telemetry.cc + ) + if(CMAKE_SYSTEM_NAME MATCHES "Android") + list(APPEND TFLITE_PROFILER_SRCS diff --git a/core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake b/core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake index e2ad257e0..a903f0af1 100644 --- a/core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake +++ b/core/iwasm/libraries/wasi-nn/cmake/wasi_nn.cmake @@ -3,27 +3,6 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) -if(WAMR_BUILD_WASI_NN_TFLITE EQUAL 1) - # Find tensorflow-lite - find_package(tensorflow_lite REQUIRED) -endif() - -if(WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1) - if(NOT DEFINED ENV{OpenVINO_DIR}) - message(FATAL_ERROR - "OpenVINO_DIR is not defined. " - "Please follow https://docs.openvino.ai/2024/get-started/install-openvino.html," - "install openvino, and set environment variable OpenVINO_DIR." - "Like OpenVINO_DIR=/usr/lib/openvino-2023.2/ cmake ..." - "Or OpenVINO_DIR=/opt/intel/openvino/ cmake ..." - ) - endif() - - list(APPEND CMAKE_MODULE_PATH $ENV{OpenVINO_DIR}) - # Find OpenVINO - find_package(OpenVINO REQUIRED COMPONENTS Runtime) -endif() - # # wasi-nn general set(WASI_NN_ROOT ${CMAKE_CURRENT_LIST_DIR}/..) @@ -42,22 +21,46 @@ add_compile_definitions( # # - tflite if(WAMR_BUILD_WASI_NN_TFLITE EQUAL 1) + find_package(tensorflow_lite REQUIRED) + add_library( wasi_nn_tflite SHARED ${WASI_NN_ROOT}/src/wasi_nn_tensorflowlite.cpp ) + target_include_directories( + wasi_nn_tflite + PUBLIC + ${tensorflow_lite_SOURCE_DIR} + ) + target_link_libraries( wasi_nn_tflite PUBLIC libiwasm tensorflow-lite ) + + install(TARGETS wasi_nn_tflite DESTINATION lib) endif() # - openvino if(WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1) + if(NOT DEFINED ENV{OpenVINO_DIR}) + message(FATAL_ERROR + "OpenVINO_DIR is not defined. " + "Please follow https://docs.openvino.ai/2024/get-started/install-openvino.html," + "install openvino, and set environment variable OpenVINO_DIR." + "Like OpenVINO_DIR=/usr/lib/openvino-2023.2/ cmake ..." + "Or OpenVINO_DIR=/opt/intel/openvino/ cmake ..." + ) + endif() + + list(APPEND CMAKE_MODULE_PATH $ENV{OpenVINO_DIR}) + # Find OpenVINO + find_package(OpenVINO REQUIRED COMPONENTS Runtime) + add_library( wasi_nn_openvino SHARED @@ -71,4 +74,37 @@ if(WAMR_BUILD_WASI_NN_OPENVINO EQUAL 1) openvino::runtime openvino::runtime::c ) -endif() \ No newline at end of file + + install(TARGETS wasi_nn_openvino DESTINATION lib) +endif() + +# - llamacpp + +if(WAMR_BUILD_WASI_NN_LLAMACPP EQUAL 1) + find_package(cjson REQUIRED) + find_package(llamacpp REQUIRED) + + add_library( + wasi_nn_llamacpp + SHARED + ${WASI_NN_ROOT}/src/wasi_nn_llamacpp.c + ) + + target_include_directories( + wasi_nn_llamacpp + PUBLIC + ${cjson_SOURCE_DIR} + ) + + target_link_libraries( + wasi_nn_llamacpp + PUBLIC + libiwasm + cjson + common + ggml + llama + ) + + install(TARGETS wasi_nn_llamacpp DESTINATION lib) +endif() diff --git a/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h b/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h index d36f5977c..3ac694fc9 100644 --- a/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h +++ b/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h @@ -43,6 +43,11 @@ typedef enum { security, // The operation failed for an unspecified reason. unknown, + // for WasmEdge-wasi-nn + end_of_sequence = 100, // End of Sequence Found. + context_full = 101, // Context Full. + prompt_tool_long = 102, // Prompt Too Long. + model_not_found = 103, // Model Not Found. } wasi_nn_error; /** @@ -140,6 +145,9 @@ typedef uint32_t graph_execution_context; typedef wasi_nn_error (*LOAD)(void *, graph_builder_array *, graph_encoding, execution_target, graph *); typedef wasi_nn_error (*LOAD_BY_NAME)(void *, const char *, uint32_t, graph *); +typedef wasi_nn_error (*LOAD_BY_NAME_WITH_CONFIG)(void *, const char *, + uint32_t, void *, uint32_t, + graph *); typedef wasi_nn_error (*INIT_EXECUTION_CONTEXT)(void *, graph, graph_execution_context *); typedef wasi_nn_error (*SET_INPUT)(void *, graph_execution_context, uint32_t, @@ -154,6 +162,7 @@ typedef wasi_nn_error (*BACKEND_DEINITIALIZE)(void *); typedef struct { LOAD load; LOAD_BY_NAME load_by_name; + LOAD_BY_NAME_WITH_CONFIG load_by_name_with_config; INIT_EXECUTION_CONTEXT init_execution_context; SET_INPUT set_input; COMPUTE compute; diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn.c b/core/iwasm/libraries/wasi-nn/src/wasi_nn.c index 0d56981fc..4697e931b 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn.c +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn.c @@ -29,7 +29,7 @@ struct backends_api_functions { void *backend_handle; api_function functions; -} lookup[autodetect] = { 0 }; +} lookup[autodetect + 1] = { 0 }; #define call_wasi_nn_func(backend_encoding, func, wasi_error, ...) \ do { \ @@ -168,14 +168,7 @@ wasi_nn_destroy() lookup[i].backend_handle = NULL; } - lookup[i].functions.init = NULL; - lookup[i].functions.deinit = NULL; - lookup[i].functions.load = NULL; - lookup[i].functions.load_by_name = NULL; - lookup[i].functions.init_execution_context = NULL; - lookup[i].functions.set_input = NULL; - lookup[i].functions.compute = NULL; - lookup[i].functions.get_output = NULL; + memset(&lookup[i].functions, 0, sizeof(api_function)); } } @@ -208,6 +201,10 @@ choose_a_backend() return ggml; } +#ifndef NDEBUG + NN_WARN_PRINTF("%s", dlerror()); +#endif + handle = dlopen(OPENVINO_BACKEND_LIB, RTLD_LAZY); if (handle) { NN_INFO_PRINTF("Using openvino backend"); @@ -215,6 +212,10 @@ choose_a_backend() return openvino; } +#ifndef NDEBUG + NN_WARN_PRINTF("%s", dlerror()); +#endif + handle = dlopen(TFLITE_BACKEND_LIB, RTLD_LAZY); if (handle) { NN_INFO_PRINTF("Using tflite backend"); @@ -222,6 +223,11 @@ choose_a_backend() return tensorflowlite; } +#ifndef NDEBUG + NN_WARN_PRINTF("%s", dlerror()); +#endif + + NN_WARN_PRINTF("No backend found"); return unknown_backend; } @@ -257,6 +263,14 @@ register_backend(void *handle, api_function *functions) } functions->load_by_name = load_by_name; + LOAD_BY_NAME_WITH_CONFIG load_by_name_with_config = + (LOAD_BY_NAME_WITH_CONFIG)dlsym(handle, "load_by_name_with_config"); + if (!load_by_name_with_config) { + NN_WARN_PRINTF("load_by_name_with_config() not found"); + // since only llama.cpp backend need to support this function + } + functions->load_by_name_with_config = load_by_name_with_config; + INIT_EXECUTION_CONTEXT init_execution_context = (INIT_EXECUTION_CONTEXT)dlsym(handle, "init_execution_context"); if (!init_execution_context) { @@ -329,21 +343,23 @@ graph_encoding_to_backend_lib_name(graph_encoding encoding) static bool detect_and_load_backend(graph_encoding backend_hint, struct backends_api_functions *backends, - graph_encoding *loaded_backed) + graph_encoding *loaded_backend) { - if (backend_hint >= autodetect) + if (backend_hint > autodetect) return false; if (backend_hint == autodetect) backend_hint = choose_a_backend(); - /* if already loaded */ - if (lookup[backend_hint].backend_handle) { - *loaded_backed = backend_hint; - return true; - } + if (backend_hint == unknown_backend) + return false; + + *loaded_backend = backend_hint; + + /* if already loaded */ + if (lookup[backend_hint].backend_handle) + return true; - *loaded_backed = backend_hint; const char *backend_lib_name = graph_encoding_to_backend_lib_name(backend_hint); if (!backend_lib_name) @@ -353,6 +369,7 @@ detect_and_load_backend(graph_encoding backend_hint, } /* WASI-NN implementation */ + #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 wasi_nn_error wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_wasm *builder, @@ -392,15 +409,15 @@ wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, goto fail; } - graph_encoding loaded_backed = autodetect; - if (!detect_and_load_backend(encoding, lookup, &loaded_backed)) { + graph_encoding loaded_backend = autodetect; + if (!detect_and_load_backend(encoding, lookup, &loaded_backend)) { res = invalid_encoding; NN_ERR_PRINTF("load backend failed"); goto fail; } WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); - wasi_nn_ctx->backend = loaded_backed; + wasi_nn_ctx->backend = loaded_backend; /* init() the backend */ call_wasi_nn_func(wasi_nn_ctx->backend, init, res, @@ -413,7 +430,6 @@ wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, if (res != success) goto fail; - wasi_nn_ctx->backend = loaded_backed; wasi_nn_ctx->is_model_loaded = true; fail: @@ -428,8 +444,6 @@ wasi_nn_error wasi_nn_load_by_name(wasm_exec_env_t exec_env, char *name, uint32_t name_len, graph *g) { - NN_DBG_PRINTF("[WASI NN] LOAD_BY_NAME %s...", name); - wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); if (!instance) { return runtime_error; @@ -446,15 +460,23 @@ wasi_nn_load_by_name(wasm_exec_env_t exec_env, char *name, uint32_t name_len, return invalid_argument; } - graph_encoding loaded_backed = autodetect; - if (detect_and_load_backend(autodetect, lookup, &loaded_backed)) { + if (name_len == 0 || name[name_len] != '\0') { + NN_ERR_PRINTF("Invalid filename"); + return invalid_argument; + } + + NN_DBG_PRINTF("[WASI NN] LOAD_BY_NAME %s...", name); + + graph_encoding loaded_backend = autodetect; + if (!detect_and_load_backend(autodetect, lookup, &loaded_backend)) { NN_ERR_PRINTF("load backend failed"); return invalid_encoding; } WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); - wasi_nn_error res; + wasi_nn_ctx->backend = loaded_backend; + wasi_nn_error res; /* init() the backend */ call_wasi_nn_func(wasi_nn_ctx->backend, init, res, &wasi_nn_ctx->backend_ctx); @@ -466,7 +488,67 @@ wasi_nn_load_by_name(wasm_exec_env_t exec_env, char *name, uint32_t name_len, if (res != success) return res; - wasi_nn_ctx->backend = loaded_backed; + wasi_nn_ctx->backend = loaded_backend; + wasi_nn_ctx->is_model_loaded = true; + return success; +} + +wasi_nn_error +wasi_nn_load_by_name_with_config(wasm_exec_env_t exec_env, char *name, + int32_t name_len, char *config, + int32_t config_len, graph *g) +{ + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + if (!instance) { + return runtime_error; + } + + if (!wasm_runtime_validate_native_addr(instance, name, name_len)) { + NN_ERR_PRINTF("name is invalid"); + return invalid_argument; + } + + if (!wasm_runtime_validate_native_addr(instance, g, + (uint64)sizeof(graph))) { + NN_ERR_PRINTF("graph is invalid"); + return invalid_argument; + } + + if (name_len == 0 || name[name_len] != '\0') { + NN_ERR_PRINTF("Invalid filename"); + return invalid_argument; + } + + if (!config || config_len == 0 || config[config_len] != '\0') { + NN_ERR_PRINTF("Invalid config"); + return invalid_argument; + } + + NN_DBG_PRINTF("[WASI NN] LOAD_BY_NAME_WITH_CONFIG %s %s...", name, config); + + graph_encoding loaded_backend = autodetect; + if (!detect_and_load_backend(autodetect, lookup, &loaded_backend)) { + NN_ERR_PRINTF("load backend failed"); + return invalid_encoding; + } + + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + wasi_nn_ctx->backend = loaded_backend; + + wasi_nn_error res; + /* init() the backend */ + call_wasi_nn_func(wasi_nn_ctx->backend, init, res, + &wasi_nn_ctx->backend_ctx); + if (res != success) + return res; + + call_wasi_nn_func(wasi_nn_ctx->backend, load_by_name_with_config, res, + wasi_nn_ctx->backend_ctx, name, name_len, config, + config_len, g); + if (res != success) + return res; + + wasi_nn_ctx->backend = loaded_backend; wasi_nn_ctx->is_model_loaded = true; return success; } @@ -608,6 +690,7 @@ static NativeSymbol native_symbols_wasi_nn[] = { #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 REG_NATIVE_FUNC(load, "(*iii*)i"), REG_NATIVE_FUNC(load_by_name, "(*i*)i"), + REG_NATIVE_FUNC(load_by_name_with_config, "(*i*i*)i"), REG_NATIVE_FUNC(init_execution_context, "(i*)i"), REG_NATIVE_FUNC(set_input, "(ii*)i"), REG_NATIVE_FUNC(compute, "(i)i"), diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_llamacpp.c b/core/iwasm/libraries/wasi-nn/src/wasi_nn_llamacpp.c new file mode 100644 index 000000000..58d29163c --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_llamacpp.c @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include "wasi_nn_types.h" +#include "utils/logger.h" +#include "llama.h" +#include "ggml.h" +#include "cJSON.h" + +// build info +extern int LLAMA_BUILD_NUMBER; +extern char const *LLAMA_COMMIT; +extern char const *LLAMA_COMPILER; +extern char const *LLAMA_BUILD_TARGET; + +// compatable with WasmEdge +// https://github.com/second-state/WasmEdge-WASINN-examples/blob/master/wasmedge-ggml/README.md#parameters +// https://github.com/WasmEdge/WasmEdge/blob/master/plugins/wasi_nn/ggml.cpp +struct wasi_nn_llama_config { + // Backend(plugin in WasmEdge) parameters: + bool enable_log; + bool enable_debug_log; + bool stream_stdout; + // embedding mode + bool embedding; + // TODO: can it be -1? + // can't bigger than ctx_size + int32_t n_predict; + char *reverse_prompt; + + // Used by LLaVA + // multi-model project file + char *mmproj; + char *image; + + // Model parameters (need to reload the model if updated): + // align to definition of struct llama_model_params + int32_t n_gpu_layers; + int32_t main_gpu; + // limited size: llama_max_devices() + float *tensor_split; + bool use_mmap; + + // Context parameters (used by the llama context): + uint32_t ctx_size; + uint32_t batch_size; + uint32_t ubatch_size; + uint32_t threads; + + // Sampling parameters (used by the llama sampling context). + float temp; + float topP; + float repeat_penalty; + float presence_penalty; + float frequency_penalty; +}; + +struct LlamaContext { + struct llama_context *ctx; + struct llama_model *model; + llama_token *prompt; + size_t prompt_len; + llama_token *generation; + size_t generation_len; + struct wasi_nn_llama_config config; +}; + +static void +wasm_edge_llama_default_configuration(struct wasi_nn_llama_config *output) +{ + output->enable_log = false; + output->enable_debug_log = false; + output->stream_stdout = false; + output->embedding = false; + output->n_predict = 512; + output->reverse_prompt = NULL; + + output->mmproj = NULL; + output->image = NULL; + + output->main_gpu = 0; + output->n_gpu_layers = 0; + output->tensor_split = NULL; + output->use_mmap = true; + + // 0 = from model + output->ctx_size = 0; + output->batch_size = 512; + output->ubatch_size = output->batch_size; + output->threads = 1; + + output->temp = 0.80; + output->topP = 0.95; + output->repeat_penalty = 1.10; + output->presence_penalty = 0.0; + output->frequency_penalty = 0.0; +} + +static void +wasm_edge_llama_apply_configuration(const char *config_json, + struct wasi_nn_llama_config *output) +{ + cJSON *root = cJSON_Parse(config_json); + if (root == NULL) { + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr != NULL) { + NN_WARN_PRINTF("Error before: %s\n", error_ptr); + } + else { + NN_WARN_PRINTF("Failed to parse JSON"); + } + return; + } + + cJSON *item = NULL; + + item = cJSON_GetObjectItem(root, "enable-log"); + if (item != NULL) { + output->enable_log = cJSON_IsTrue(item); + NN_DBG_PRINTF("apply enable-log %d", output->enable_log); + } + + item = cJSON_GetObjectItem(root, "enable-debug-log"); + if (item != NULL) { + output->enable_debug_log = cJSON_IsTrue(item); + NN_DBG_PRINTF("apply enable-debug-log %d", output->enable_debug_log); + } + + item = cJSON_GetObjectItem(root, "stream-stdout"); + if (item != NULL) { + output->stream_stdout = cJSON_IsTrue(item); + NN_DBG_PRINTF("apply stream-stdout %d", output->stream_stdout); + } + + item = cJSON_GetObjectItem(root, "embedding"); + if (item != NULL) { + output->embedding = cJSON_IsTrue(item); + NN_DBG_PRINTF("apply embedding %d", output->embedding); + } + + item = cJSON_GetObjectItem(root, "n-predict"); + if (item != NULL) { + output->n_predict = (int32_t)cJSON_GetNumberValue(item); + NN_DBG_PRINTF("apply n-predict %d", output->n_predict); + } + + item = cJSON_GetObjectItem(root, "n-gpu-layers"); + if (item != NULL) { + output->n_gpu_layers = (int32_t)cJSON_GetNumberValue(item); + NN_DBG_PRINTF("apply n_gpu_layers %d", output->n_gpu_layers); + } + + item = cJSON_GetObjectItem(root, "ctx-size"); + if (item != NULL) { + output->ctx_size = (uint32_t)cJSON_GetNumberValue(item); + NN_DBG_PRINTF("apply ctx-size %d", output->ctx_size); + } + + // more ... + + cJSON_Delete(root); +} + +static struct llama_model_params +llama_model_params_from_wasi_nn_llama_config( + struct wasi_nn_llama_config *config) +{ + struct llama_model_params result = llama_model_default_params(); + + // TODO: support more + result.main_gpu = config->main_gpu; + result.n_gpu_layers = config->n_gpu_layers; + result.use_mmap = config->use_mmap; + + return result; +} + +static struct llama_context_params +llama_context_params_from_wasi_nn_llama_config( + struct wasi_nn_llama_config *config) +{ + struct llama_context_params result = llama_context_default_params(); + + // TODO: support more + result.n_ctx = config->ctx_size; + // result.embeddings = config->embedding; + + return result; +} + +static void +llama_batch_clear(struct llama_batch *batch) +{ + batch->n_tokens = 0; +} + +static void +llama_batch_add(struct llama_batch *batch, llama_token id, llama_pos pos, + llama_seq_id *seq_ids, size_t seq_ids_len, bool logits) +{ + batch->token[batch->n_tokens] = id; + batch->pos[batch->n_tokens] = pos; + batch->n_seq_id[batch->n_tokens] = seq_ids_len; + for (size_t i = 0; i < seq_ids_len; ++i) { + batch->seq_id[batch->n_tokens][i] = seq_ids[i]; + } + batch->logits[batch->n_tokens] = logits; + + batch->n_tokens++; +} + +// always output ERROR and WARN +// INFO needs enable_log +// DEBUG needs enable_debug_log +static void +llama_log_callback_local(enum ggml_log_level level, const char *text, + void *user_data) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)user_data; + + if (level == GGML_LOG_LEVEL_DEBUG && !backend_ctx->config.enable_debug_log) + return; + + if (level == GGML_LOG_LEVEL_INFO && !backend_ctx->config.enable_log) + return; + + printf("%s", text); +} + +static void +llama_build_output_metadata(const struct LlamaContext *backend_ctx, + char *output_buf, size_t output_buf_size) +{ + snprintf(output_buf, output_buf_size, + "{\"input_tokens\":%ld, \"output_tokens\":%ld, " + "\"llama_build_number\":%d," + "\"llama_commit\":\"%s\"}", + backend_ctx->prompt_len, backend_ctx->generation_len, + LLAMA_BUILD_NUMBER, LLAMA_COMMIT); +} + +__attribute__((visibility("default"))) wasi_nn_error +init_backend(void **ctx) +{ + struct LlamaContext *backend_ctx = calloc(1, sizeof(struct LlamaContext)); + if (!backend_ctx) { + NN_ERR_PRINTF("Allocate for OpenVINOContext failed"); + return runtime_error; + } + + llama_backend_init(); + // llama_numa_init(); + llama_log_set(llama_log_callback_local, backend_ctx); + +#ifndef NDEBUG + NN_INFO_PRINTF("llama_build_number: % d, llama_commit: %s, llama_compiler: " + "%s, llama_build_target: %s", + LLAMA_BUILD_NUMBER, LLAMA_COMMIT, LLAMA_COMPILER, + LLAMA_BUILD_TARGET); +#endif + + *ctx = (void *)backend_ctx; + return success; +} + +__attribute__((visibility("default"))) wasi_nn_error +deinit_backend(void *ctx) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)ctx; + + if (!backend_ctx) + return invalid_argument; + + if (backend_ctx->generation) + free(backend_ctx->generation); + + if (backend_ctx->prompt) + free(backend_ctx->prompt); + + if (backend_ctx->ctx) + llama_free(backend_ctx->ctx); + + if (backend_ctx->model) + llama_free_model(backend_ctx->model); + + llama_backend_free(); + + os_free(backend_ctx); + return success; +} + +__attribute__((visibility("default"))) wasi_nn_error +load(void *ctx, graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g) +{ + return unsupported_operation; +} + +static wasi_nn_error +__load_by_name_with_configuration(void *ctx, const char *filename, graph *g) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)ctx; + + // make sure backend_ctx->config is initialized + + struct llama_model_params model_params = + llama_model_params_from_wasi_nn_llama_config(&backend_ctx->config); + struct llama_model *model = + llama_load_model_from_file(filename, model_params); + if (model == NULL) { + NN_ERR_PRINTF("Failed to load model from file %s", filename); + return runtime_error; + } + +#ifndef NDEBUG + char buf[128] = { 0 }; + llama_model_desc(model, buf, 127); + NN_INFO_PRINTF("Model desc %s", buf); +#endif + + backend_ctx->model = model; + + return success; +} + +__attribute__((visibility("default"))) wasi_nn_error +load_by_name(void *ctx, const char *filename, uint32_t filename_len, graph *g) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)ctx; + + // use default params + wasm_edge_llama_default_configuration(&backend_ctx->config); + return __load_by_name_with_configuration(ctx, filename, g); +} + +__attribute__((visibility("default"))) wasi_nn_error +load_by_name_with_config(void *ctx, const char *filename, uint32_t filename_len, + const char *config, uint32_t config_len, graph *g) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)ctx; + + wasm_edge_llama_default_configuration(&backend_ctx->config); + + if (config != NULL) { + // parse wasmedge config + wasm_edge_llama_apply_configuration(config, &backend_ctx->config); + } + else { + NN_INFO_PRINTF("No configuration provided, use default"); + } + + return __load_by_name_with_configuration(ctx, filename, g); +} + +// It is assumed that model params shouldn't be changed in Config stage. +// We only load the model once in the Load stage. +__attribute__((visibility("default"))) wasi_nn_error +init_execution_context(void *ctx, graph g, graph_execution_context *exec_ctx) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)ctx; + + struct llama_context_params ctx_params = + llama_context_params_from_wasi_nn_llama_config(&backend_ctx->config); + struct llama_context *llama_ctx = + llama_new_context_with_model(backend_ctx->model, ctx_params); + if (llama_ctx == NULL) { + NN_ERR_PRINTF("Failed to create context for model"); + return runtime_error; + } + + backend_ctx->ctx = llama_ctx; + + NN_INFO_PRINTF("n_predict = %d, n_ctx = %d", backend_ctx->config.n_predict, + llama_n_ctx(backend_ctx->ctx)); + return success; +} + +__attribute__((visibility("default"))) wasi_nn_error +set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index, + tensor *wasi_nn_tensor) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)ctx; + // tensor->data is the prompt string. ends with \0 + char *prompt_text = (char *)wasi_nn_tensor->data; + +#ifndef NDEBUG + NN_DBG_PRINTF("--------------------------------------------------"); + NN_DBG_PRINTF("prompt_text: %s", prompt_text); + NN_DBG_PRINTF("--------------------------------------------------"); +#endif + + // tokenize the prompt + uint32_t n_token_max = llama_n_ctx(backend_ctx->ctx); + uint32_t prompt_text_len = strlen(prompt_text); + + if (backend_ctx->prompt == NULL) { + backend_ctx->prompt = calloc(n_token_max, sizeof(llama_token)); + if (backend_ctx->prompt == NULL) { + NN_ERR_PRINTF("Failed to allocate tokens_list"); + return runtime_error; + } + } + + int32_t n_tokens = + llama_tokenize(backend_ctx->model, prompt_text, prompt_text_len, + backend_ctx->prompt, n_token_max, true, false); + if (n_tokens < 0) { + NN_ERR_PRINTF("Failed to tokenize prompt text"); + return runtime_error; + } + + backend_ctx->prompt_len = n_tokens; + + // make sure the KV cache is big enough to hold all the prompt and generated + // tokens + int n_kv_req = n_tokens + (backend_ctx->config.n_predict - n_tokens); + if (n_kv_req < 0 || (uint32_t)n_kv_req > n_token_max) { + NN_ERR_PRINTF("the required KV cache size is not big enough, either " + "reduce n_predict or increase n_ctx"); + return runtime_error; + } + + return success; +} + +__attribute__((visibility("default"))) wasi_nn_error +compute(void *ctx, graph_execution_context exec_ctx) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)ctx; + wasi_nn_error ret = runtime_error; + + // reset the generation buffer + if (backend_ctx->generation == NULL) { + backend_ctx->generation = + calloc(backend_ctx->config.n_predict, sizeof(llama_token)); + if (backend_ctx->generation == NULL) { + NN_ERR_PRINTF("Failed to allocate generation"); + return runtime_error; + } + } + + backend_ctx->generation_len = 0; + + // check KV cache + uint32_t n_ctx = llama_n_ctx(backend_ctx->ctx); + if (n_ctx <= backend_ctx->generation_len) { + NN_ERR_PRINTF( + "ctx_size(%u) is not big enough(<%ld), please increase it", n_ctx, + backend_ctx->generation_len); + return context_full; + } + + // prepare the batch + struct llama_batch batch = + llama_batch_init(backend_ctx->config.batch_size, 0, 1); + + // evaluate the initial prompt + llama_seq_id seq_ids[1] = { 0 }; + for (size_t i = 0; i < backend_ctx->prompt_len; i++) { + llama_batch_add(&batch, backend_ctx->prompt[i], i, seq_ids, + sizeof(seq_ids) / sizeof(seq_ids[0]), false); + } + + batch.logits[batch.n_tokens - 1] = true; + + if (batch.n_tokens > backend_ctx->config.n_predict) { + NN_DBG_PRINTF("n_predict(%d) is not big enough(%d), please increase it", + backend_ctx->config.n_predict, batch.n_tokens); + return prompt_tool_long; + } + + if (llama_decode(backend_ctx->ctx, batch) != 0) { + NN_ERR_PRINTF("First decode failed"); + return runtime_error; + } + + // main loop + int32_t n_cur = batch.n_tokens; + int n_decode = 0; + int32_t n_vocab = llama_n_vocab(backend_ctx->model); + llama_token_data *candidates = NULL; + + candidates = calloc(n_vocab, sizeof(llama_token_data)); + if (candidates == NULL) { + NN_ERR_PRINTF("Failed to allocate candidates"); + goto fail; + } + + while (n_cur <= backend_ctx->config.n_predict) { + // sample the next token + float *logits = + llama_get_logits_ith(backend_ctx->ctx, batch.n_tokens - 1); + + memset(candidates, 0, sizeof(llama_token_data) * n_vocab); + for (llama_token token_id = 0; token_id < n_vocab; token_id++) { + candidates[token_id].id = token_id; + candidates[token_id].logit = logits[token_id]; + candidates[token_id].p = 0.0f; + } + + llama_token_data_array candidates_p = { candidates, n_vocab, false }; + + // sample the most likely token + llama_token new_token_id = + llama_sample_token_greedy(backend_ctx->ctx, &candidates_p); + + backend_ctx->generation[backend_ctx->generation_len++] = new_token_id; + +#ifndef NDEBUG + { + char buf[128] = { 0 }; + llama_token_to_piece(backend_ctx->model, new_token_id, buf, 120, 0, + true); + printf("%d(%s),", new_token_id, buf); + } +#endif + + // is it an end of generation? + if (llama_token_is_eog(backend_ctx->model, new_token_id)) { + printf("\n"); + NN_INFO_PRINTF("reach the end of generation"); + break; + } + + // prepare the next batch + llama_batch_clear(&batch); + // push this new token for next evaluation + llama_batch_add(&batch, new_token_id, n_cur, seq_ids, + sizeof(seq_ids) / sizeof(seq_ids[0]), true); + n_decode++; + n_cur++; + + if (llama_decode(backend_ctx->ctx, batch) != 0) { + NN_ERR_PRINTF("Secondary decode failed"); + goto fail; + } + } + + printf("\n"); + ret = success; +fail: + llama_batch_free(batch); + if (candidates != NULL) { + free(candidates); + } + return ret; +} + +__attribute__((visibility("default"))) wasi_nn_error +get_output(void *ctx, graph_execution_context exec_ctx, uint32_t index, + tensor_data output_tensor, uint32_t *output_tensor_size) +{ + struct LlamaContext *backend_ctx = (struct LlamaContext *)ctx; + + // Compatibility with WasmEdge + if (index > 1) { + NN_ERR_PRINTF("Invalid output index %d", index); + return invalid_argument; + } + + // Index 1 is for the metadata of the outputs. + if (index == 1) { + char output_metadata[128] = { 0 }; + llama_build_output_metadata(backend_ctx, output_metadata, 127); + + if (backend_ctx->config.stream_stdout) { + printf("%s\n", output_metadata); + } + + memcpy(output_tensor, output_metadata, strlen(output_metadata)); + *output_tensor_size = strlen(output_metadata); + return success; + } + + // token -> piece -> output_tensor + if (backend_ctx->config.stream_stdout) { + printf("\n"); + } + + size_t end_pos = 0; + for (size_t i = 0; i < backend_ctx->generation_len; i++) { + char buf[128] = { 0 }; + llama_token_to_piece(backend_ctx->model, backend_ctx->generation[i], + buf, 120, 0, true); + + if (backend_ctx->config.stream_stdout) { + printf("%s", buf); + } + + memcpy(output_tensor + end_pos, buf, strlen(buf)); + end_pos += strlen(buf); + } + + if (backend_ctx->config.stream_stdout) { + printf("\n"); + } + + *output_tensor_size = end_pos; + return success; +} diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu b/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu index a33bebff5..67bfbfe0e 100644 --- a/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu @@ -14,19 +14,32 @@ WORKDIR /usr/local/share/ca-certificates/cacert.org RUN wget -qP /usr/local/share/ca-certificates/cacert.org http://www.cacert.org/certs/root.crt http://www.cacert.org/certs/class3.crt \ && update-ca-certificates +# need a newer cmake +RUN apt-get purge -y cmake + +ARG CMAKE_VER=3.27.0 +RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh \ + -q -O /tmp/cmake-install.sh \ + && chmod u+x /tmp/cmake-install.sh \ + && mkdir /opt/cmake-${CMAKE_VER} \ + && /tmp/cmake-install.sh --skip-license --prefix=/opt/cmake-${CMAKE_VER} \ + && rm /tmp/cmake-install.sh \ + && ln -s /opt/cmake-${CMAKE_VER}/bin/* /usr/local/bin + WORKDIR /home/wamr COPY . . RUN git config --global http.sslCAinfo /etc/ssl/certs/ca-certificates.crt WORKDIR /home/wamr/product-mini/platforms/linux RUN rm -rf build \ - && cmake -S . -B build -DWAMR_BUILD_WASI_NN=1 \ + && cmake -S . -B build\ + -DWAMR_BUILD_WASI_NN=1 -DWAMR_BUILD_WASI_NN_TFLITE=1\ && cmake --build build -j "$(grep -c ^processor /proc/cpuinfo)" FROM ubuntu:22.04 -COPY --from=base /home/wamr/product-mini/platforms/linux/build/iwasm /usr/bin/iwasm -COPY --from=base /home/wamr/product-mini/platforms/linux/build/libiwasm.so /lib/libiwasm.so -COPY --from=base /home/wamr/product-mini/platforms/linux/build/libwasi-nn-*.so /lib/ +COPY --from=base /home/wamr/product-mini/platforms/linux/build/iwasm /usr/bin +COPY --from=base /home/wamr/product-mini/platforms/linux/build/lib*.so /usr/lib +ENV LD_LIBRARY_PATH=/usr/lib ENTRYPOINT [ "iwasm" ] diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu b/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu index 49ee51a15..8fe82510a 100644 --- a/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu @@ -14,14 +14,26 @@ WORKDIR /usr/local/share/ca-certificates/cacert.org RUN wget -qP /usr/local/share/ca-certificates/cacert.org http://www.cacert.org/certs/root.crt http://www.cacert.org/certs/class3.crt \ && update-ca-certificates +# need a newer cmake +RUN apt-get purge -y cmake + +ARG CMAKE_VER=3.27.0 +RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh \ + -q -O /tmp/cmake-install.sh \ + && chmod u+x /tmp/cmake-install.sh \ + && mkdir /opt/cmake-${CMAKE_VER} \ + && /tmp/cmake-install.sh --skip-license --prefix=/opt/cmake-${CMAKE_VER} \ + && rm /tmp/cmake-install.sh \ + && ln -s /opt/cmake-${CMAKE_VER}/bin/* /usr/local/bin + WORKDIR /home/wamr COPY . . RUN git config --global http.sslCAinfo /etc/ssl/certs/ca-certificates.crt -WORKDIR /home/wamr/product-mini/platforms/linux/build +WORKDIR /home/wamr/product-mini/platforms/linux RUN rm -rf build \ && cmake -S . -B build \ - -DWAMR_BUILD_WASI_NN=1 \ + -DWAMR_BUILD_WASI_NN=1 -DWAMR_BUILD_WASI_NN_TFLITE=1\ -DWAMR_BUILD_WASI_NN_ENABLE_GPU=1 \ && cmake --build build -j "$(grep -c ^processor /proc/cpuinfo)" @@ -40,8 +52,8 @@ RUN mkdir -p /etc/OpenCL/vendors && \ ENV NVIDIA_VISIBLE_DEVICES=all ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility -COPY --from=base /home/wamr/product-mini/platforms/linux/build/iwasm /usr/bin/iwasm -COPY --from=base /home/wamr/product-mini/platforms/linux/build/libiwasm.so /lib/libiwasm.so -COPY --from=base /home/wamr/product-mini/platforms/linux/build/libwasi-nn-*.so /lib/ +COPY --from=base /home/wamr/product-mini/platforms/linux/build/iwasm /usr/bin +COPY --from=base /home/wamr/product-mini/platforms/linux/build/lib*.so /usr/lib +ENV LD_LIBRARY_PATH=/usr/lib ENTRYPOINT [ "iwasm" ] diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.tpu b/core/iwasm/libraries/wasi-nn/test/Dockerfile.tpu index a0ae29a63..6a7dc1534 100644 --- a/core/iwasm/libraries/wasi-nn/test/Dockerfile.tpu +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.tpu @@ -14,22 +14,35 @@ WORKDIR /usr/local/share/ca-certificates/cacert.org RUN wget -qP /usr/local/share/ca-certificates/cacert.org http://www.cacert.org/certs/root.crt http://www.cacert.org/certs/class3.crt \ && update-ca-certificates +# need a newer cmake +RUN apt-get purge -y cmake + +ARG CMAKE_VER=3.27.0 +RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh \ + -q -O /tmp/cmake-install.sh \ + && chmod u+x /tmp/cmake-install.sh \ + && mkdir /opt/cmake-${CMAKE_VER} \ + && /tmp/cmake-install.sh --skip-license --prefix=/opt/cmake-${CMAKE_VER} \ + && rm /tmp/cmake-install.sh \ + && ln -s /opt/cmake-${CMAKE_VER}/bin/* /usr/local/bin + WORKDIR /home/wamr COPY . . RUN git config --global http.sslCAinfo /etc/ssl/certs/ca-certificates.crt WORKDIR /home/wamr/product-mini/platforms/linux RUN rm -rf build \ - && cmake -S . -B build -DWAMR_BUILD_WASI_NN=1 \ - -DWAMR_BUILD_WASI_NN=1 \ + && cmake -S . -B build\ + -DWAMR_BUILD_WASI_NN=1\ + -DWAMR_BUILD_WASI_NN_TFLITE=1\ -DWAMR_BUILD_WASI_NN_ENABLE_EXTERNAL_DELEGATE=1 \ -DWAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH="libedgetpu.so.1.0" \ -DWAMR_BUILD_WASI_NN_ENABLE_GPU=1 \ && cmake --build build -j "$(grep -c ^processor /proc/cpuinfo)" -RUN cp /home/wamr/product-mini/platforms/linux/build/iwasm /usr/bin/iwasm \ - && cp /home/wamr/product-mini/platforms/linux/build/libiwasm.so /lib/libiwasm.so \ - && cp /home/wamr/product-mini/platforms/linux/build/libwasi-nn-*.so /lib/ +RUN cp /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm \ + && cp /home/wamr/product-mini/platforms/linux/build/lib*.so /usr/lib +ENV LD_LIBRARY_PATH=/usr/lib WORKDIR /assets ENTRYPOINT [ "iwasm" ] diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate b/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate index f078045b9..e05b30119 100644 --- a/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate @@ -21,6 +21,18 @@ RUN apt-get update && apt-get install -y wget ca-certificates --no-install-recom && update-ca-certificates \ && git config --global http.sslCAinfo /etc/ssl/certs/ca-certificates.crt +# need a newer cmake +RUN apt-get purge -y cmake + +ARG CMAKE_VER=3.27.0 +RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh \ + -q -O /tmp/cmake-install.sh \ + && chmod u+x /tmp/cmake-install.sh \ + && mkdir /opt/cmake-${CMAKE_VER} \ + && /tmp/cmake-install.sh --skip-license --prefix=/opt/cmake-${CMAKE_VER} \ + && rm /tmp/cmake-install.sh \ + && ln -s /opt/cmake-${CMAKE_VER}/bin/* /usr/local/bin + # Build TensorFlow Lite VX delegate default built for x86-64 simulator WORKDIR /tmp RUN git clone https://github.com/VeriSilicon/TIM-VX.git tim-vx \ @@ -89,7 +101,6 @@ ENV VSIMULATOR_CONFIG=czl ENV LD_LIBRARY_PATH=/tmp/tim-vx/prebuilt-sdk/x86_64_linux/lib:/usr/local/lib:/lib/x86_64-linux-gnu/:/lib64/:/usr/lib:$LD_LIBRARY_PATH - # Build WASI-NN WORKDIR /home/wamr @@ -102,12 +113,14 @@ RUN cmake \ -DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}:/usr/local/lib/ \ -DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}:/usr/local/include/ \ -DWAMR_BUILD_WASI_NN=1 \ + -DWAMR_BUILD_WASI_NN_TFLITE=1\ -DWAMR_BUILD_WASI_NN_ENABLE_EXT=1 \ -DWASI_NN_EXT_DELEGATE_PATH="/usr/lib/libvx_delegate.so" \ .. RUN make -j "$(grep -c ^processor /proc/cpuinfo)" -RUN cp /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm +RUN cp /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm \ + && cp /home/wamr/product-mini/platforms/linux/build/lib*.so /usr/lib ENTRYPOINT [ "/run/iwasm" ] diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke b/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke index 261c77261..fe3a8c512 100644 --- a/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-smoke @@ -63,21 +63,35 @@ WORKDIR /workspaces/wasmedge-wasinn-examples RUN git clone --depth 1 https://github.com/second-state/WasmEdge-WASINN-examples.git . COPY core/iwasm/libraries/wasi-nn/test/bump_wasi_nn_to_0_6_0.patch . RUN git apply ./bump_wasi_nn_to_0_6_0.patch -# recompile with wasi-nn 0.6.0 -RUN cd openvino-mobilenet-image/rust && cargo build --target=wasm32-wasi -RUN cd openvino-mobilenet-raw/rust && cargo build --target=wasm32-wasi -RUN cd openvino-road-segmentation-adas/openvino-road-seg-adas && cargo build --target=wasm32-wasi -RUN cd tflite-birds_v1-image/rust && cargo build --target=wasm32-wasi -# preparation -RUN cd openvino-mobilenet-image \ +# recompile with wasi-nn 0.6.0 +WORKDIR /workspaces/wasmedge-wasinn-examples/openvino-mobilenet-image/ +RUN pushd rust \ + && cargo build --target=wasm32-wasi \ + && popd \ && ./download_mobilenet.sh . \ && ls -l mobilenet.xml mobilenet.bin -RUN cd openvino-mobilenet-raw \ +WORKDIR /workspaces/wasmedge-wasinn-examples/openvino-mobilenet-raw/ +RUN pushd rust \ + && cargo build --target=wasm32-wasi \ + && popd \ && ./download_mobilenet.sh . \ && ls -l mobilenet.xml mobilenet.bin tensor-1x224x224x3-f32.bgr +WORKDIR /workspaces/wasmedge-wasinn-examples/openvino-road-segmentation-adas/ +RUN pushd openvino-road-seg-adas \ + && cargo build --target=wasm32-wasi + +WORKDIR /workspaces/wasmedge-wasinn-examples/tflite-birds_v1-image/ +RUN pushd rust \ + && cargo build --target=wasm32-wasi + +# mount models when running +WORKDIR /workspaces/wasmedge-wasinn-examples/wasmedge-ggml/qwen +RUN wget --progress=dot:giga https://www.modelscope.cn/models/qwen/Qwen1.5-0.5B-Chat-GGUF/resolve/master/qwen1_5-0_5b-chat-q2_k.gguf +RUN cargo build --target=wasm32-wasi + # # iwasm. build from source WORKDIR /workspaces/wamr @@ -88,15 +102,16 @@ WORKDIR /workspaces/wamr/product-mini/platforms/linux RUN OpenVINO_DIR=/usr/lib/openvino-2023.2.0 \ cmake -S . -B build \ -DWAMR_BUILD_WASI_NN=1 -DWAMR_BUILD_WASI_EPHEMERAL_NN=1 \ - -DWAMR_BUILD_WASI_NN_OPENVINO=1 -DWAMR_BUILD_WASI_NN_TFLITE=1 \ - && cmake --build build - -ENV PATH=/workspaces/wamr/product-mini/platforms/linux/build:${PATH} -ENV LD_LIBRARY_PATH=/workspaces/wamr/product-mini/platforms/linux/build + -DWAMR_BUILD_WASI_NN_OPENVINO=1 \ + -DWAMR_BUILD_WASI_NN_TFLITE=1 \ + -DWAMR_BUILD_WASI_NN_LLAMACPP=1 \ + && cmake --build build \ + && cmake --install build + +ENV LD_LIBRARY_PATH=/usr/local/lib # add smoke test script COPY core/iwasm/libraries/wasi-nn/test/run_smoke_test.py / -# WORKDIR /workspaces/wasmedge-wasinn-examples CMD ["python3", "/run_smoke_test.py"] diff --git a/core/iwasm/libraries/wasi-nn/test/build.sh b/core/iwasm/libraries/wasi-nn/test/build.sh index da6cfa5f8..dda400f16 100755 --- a/core/iwasm/libraries/wasi-nn/test/build.sh +++ b/core/iwasm/libraries/wasi-nn/test/build.sh @@ -8,9 +8,9 @@ CURR_PATH=$(cd $(dirname $0) && pwd -P) # WASM application that uses WASI-NN /opt/wasi-sdk/bin/clang \ + --target=wasm32-wasi \ + -DNN_LOG_LEVEL=1 \ -Wl,--allow-undefined \ - -Wl,--strip-all,--no-entry \ - --sysroot=/opt/wasi-sdk/share/wasi-sysroot \ -I../include -I../src/utils \ -o test_tensorflow.wasm \ test_tensorflow.c utils.c @@ -28,9 +28,9 @@ python3 sum.py cd ${CURR_PATH} /opt/wasi-sdk/bin/clang \ + --target=wasm32-wasi \ + -DNN_LOG_LEVEL=1 \ -Wl,--allow-undefined \ - -Wl,--strip-all,--no-entry \ - --sysroot=/opt/wasi-sdk/share/wasi-sysroot \ -I../include -I../src/utils \ -o test_tensorflow_quantized.wasm \ test_tensorflow_quantized.c utils.c diff --git a/core/iwasm/libraries/wasi-nn/test/requirements.txt b/core/iwasm/libraries/wasi-nn/test/requirements.txt index 177c22c19..1643b91b0 100644 --- a/core/iwasm/libraries/wasi-nn/test/requirements.txt +++ b/core/iwasm/libraries/wasi-nn/test/requirements.txt @@ -1,2 +1,2 @@ tensorflow==2.12.1 -numpy==1.26.4 +numpy==1.24.4 diff --git a/core/iwasm/libraries/wasi-nn/test/run_smoke_test.py b/core/iwasm/libraries/wasi-nn/test/run_smoke_test.py index a62d9cb7a..304b0c977 100644 --- a/core/iwasm/libraries/wasi-nn/test/run_smoke_test.py +++ b/core/iwasm/libraries/wasi-nn/test/run_smoke_test.py @@ -260,6 +260,63 @@ def execute_openvino_road_segmentation_adas( print("------------------------------------------------------------") +def execute_wasmedge_ggml_qwen(iwasm_bin: str, wasmedge_bin: str, cwd: Path): + iwasm_args = ["--dir=."] + wasm_file = ["./target/wasm32-wasi/debug/wasmedge-ggml-qwen.wasm"] + wasm_args = ["./qwen1_5-0_5b-chat-q2_k.gguf"] + + cmd = [iwasm_bin] + cmd.extend(iwasm_args) + cmd.extend(wasm_file) + cmd.extend(wasm_args) + + # print(f'Execute: {" ".join(cmd)}') + + prompt = "what is the capital of Pakistan" + + with subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=cwd, + ) as p: + # USER + p.stdout.readline() + + p.stdin.write(b"hi\n") + p.stdin.flush() + # ASSITANT + p.stdout.readline() + # xxx + p.stdout.readline() + # USER + p.stdout.readline() + + p.stdin.write(prompt.encode()) + p.stdin.write(b"\n") + p.stdin.flush() + # ASSITANT + p.stdout.readline() + # xxx + answer = p.stdout.readline().decode("utf-8") + # USER + p.stdout.readline() + + p.terminate() + + if "Karachi" in answer: + print(f"- wasmedge_ggml_qwen. PASS") + return + + print(f"- wasmedge_ggml_qwen. FAILED") + print("------------------------------------------------------------") + pprint(answer) + print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<") + pprint("Karachi") + print("------------------------------------------------------------") + + def execute_wasmedge_wasinn_examples(iwasm_bin: str, wasmedge_bin: str): assert Path.cwd().name == "wasmedge-wasinn-examples" assert shutil.which(iwasm_bin) @@ -282,6 +339,9 @@ def execute_wasmedge_wasinn_examples(iwasm_bin: str, wasmedge_bin: str): iwasm_bin, wasmedge_bin, openvino_road_segmentation_adas_dir ) + wasmedge_ggml_qwem_dir = Path.cwd().joinpath("./wasmedge-ggml/qwen") + execute_wasmedge_ggml_qwen(iwasm_bin, wasmedge_bin, wasmedge_ggml_qwem_dir) + if __name__ == "__main__": execute_wasmedge_wasinn_examples("iwasm", "wasmedge") diff --git a/core/iwasm/libraries/wasi-nn/test/utils.c b/core/iwasm/libraries/wasi-nn/test/utils.c index c499adc5b..9e43ec985 100644 --- a/core/iwasm/libraries/wasi-nn/test/utils.c +++ b/core/iwasm/libraries/wasi-nn/test/utils.c @@ -5,6 +5,7 @@ #include "utils.h" #include "logger.h" +#include "wasi_nn.h" #include #include @@ -57,7 +58,7 @@ wasm_load(char *model_name, graph *g, execution_target target) wasi_nn_error wasm_load_by_name(const char *model_name, graph *g) { - wasm_nn_error res = load_by_name(model_name, g); + wasi_nn_error res = load_by_name(model_name, g); return res; } diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index 4863527d6..e272b3014 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -992,8 +992,8 @@ gci_dump(gc_heap_t *heap) os_printf("#%d %08" PRIx32 " %" PRIx32 " %d %d" " %c %" PRId32 "\n", - i, (int32)((char *)cur - (char *)heap->base_addr), (int32)ut, - p, mark, inuse, (int32)hmu_obj_size(size)); + i, (uint32)((char *)cur - (char *)heap->base_addr), + (uint32)ut, p, mark, inuse, (int32)hmu_obj_size(size)); #if BH_ENABLE_GC_VERIFY != 0 if (inuse == 'V') { gc_object_prefix_t *prefix = (gc_object_prefix_t *)(cur + 1); diff --git a/core/shared/platform/alios/platform_internal.h b/core/shared/platform/alios/platform_internal.h index d2897a6b5..bdf3d073f 100644 --- a/core/shared/platform/alios/platform_internal.h +++ b/core/shared/platform/alios/platform_internal.h @@ -77,7 +77,7 @@ typedef void *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index 4449f21e8..7abf863f8 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -151,7 +151,7 @@ typedef DIR *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index c76abf137..1d972f5fa 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -138,18 +138,25 @@ os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) /* memory hasn't been mapped or was mapped failed previously */ if (addr == MAP_FAILED) { - /* try 5 times */ - for (i = 0; i < 5; i++) { + /* try 5 times on EAGAIN or ENOMEM, and keep retrying on EINTR */ + i = 0; + while (i < 5) { addr = mmap(hint, request_size, map_prot, map_flags, file, 0); if (addr != MAP_FAILED) break; + if (errno == EINTR) + continue; + if (errno != EAGAIN && errno != ENOMEM) { + break; + } + i++; } } if (addr == MAP_FAILED) { -#if BH_ENABLE_TRACE_MMAP != 0 - os_printf("mmap failed\n"); -#endif + os_printf("mmap failed with errno: %d, hint: %p, size: %" PRIu64 + ", prot: %d, flags: %d", + errno, hint, request_size, map_prot, map_flags); return NULL; } diff --git a/core/shared/platform/cosmopolitan/platform_internal.h b/core/shared/platform/cosmopolitan/platform_internal.h index 726021160..5c73ed5a6 100644 --- a/core/shared/platform/cosmopolitan/platform_internal.h +++ b/core/shared/platform/cosmopolitan/platform_internal.h @@ -69,7 +69,7 @@ typedef DIR *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index 1cbecdc20..928aad724 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -114,7 +114,7 @@ typedef DIR *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/esp-idf/platform_internal.h b/core/shared/platform/esp-idf/platform_internal.h index e0091bee1..580a06d90 100644 --- a/core/shared/platform/esp-idf/platform_internal.h +++ b/core/shared/platform/esp-idf/platform_internal.h @@ -145,7 +145,7 @@ typedef DIR *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/freebsd/platform_internal.h b/core/shared/platform/freebsd/platform_internal.h index bfdfe1493..01a6e824f 100644 --- a/core/shared/platform/freebsd/platform_internal.h +++ b/core/shared/platform/freebsd/platform_internal.h @@ -115,7 +115,7 @@ os_set_signal_number_for_blocking_op(int signo); typedef int os_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index b1c3b4f4a..37b8399b8 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -379,19 +379,19 @@ os_sem_unlink(const char *name); * Initialize process-global state for os_wakeup_blocking_op. */ int -os_blocking_op_init(); +os_blocking_op_init(void); /** * Start accepting os_wakeup_blocking_op requests for the calling thread. */ void -os_begin_blocking_op(); +os_begin_blocking_op(void); /** * Stop accepting os_wakeup_blocking_op requests for the calling thread. */ void -os_end_blocking_op(); +os_end_blocking_op(void); /** * Wake up the specified thread. @@ -1586,7 +1586,7 @@ os_closedir(os_dir_stream dir_stream); * @return the invalid directory stream */ os_dir_stream -os_get_invalid_dir_stream(); +os_get_invalid_dir_stream(void); /** * Checks whether the given directory stream is valid. An invalid directory @@ -1605,7 +1605,7 @@ os_is_dir_stream_valid(os_dir_stream *dir_stream); * @return the invalid handle */ os_file_handle -os_get_invalid_handle(); +os_get_invalid_handle(void); /** * Checks whether the given file handle is valid. An invalid handle is diff --git a/core/shared/platform/linux-sgx/platform_internal.h b/core/shared/platform/linux-sgx/platform_internal.h index 2cc34dfca..66960ad28 100644 --- a/core/shared/platform/linux-sgx/platform_internal.h +++ b/core/shared/platform/linux-sgx/platform_internal.h @@ -74,7 +74,7 @@ typedef DIR *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index aeddc4ccf..865180273 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -127,7 +127,7 @@ typedef DIR *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h index 0b54d85a9..fef2122da 100644 --- a/core/shared/platform/nuttx/platform_internal.h +++ b/core/shared/platform/nuttx/platform_internal.h @@ -137,7 +137,7 @@ typedef DIR *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/riot/platform_internal.h b/core/shared/platform/riot/platform_internal.h index 24a1d6c86..11f2ba0a7 100644 --- a/core/shared/platform/riot/platform_internal.h +++ b/core/shared/platform/riot/platform_internal.h @@ -89,7 +89,7 @@ int isnan(double x); #endif static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/rt-thread/platform_internal.h b/core/shared/platform/rt-thread/platform_internal.h index 69d6d5581..b9b8c78c8 100644 --- a/core/shared/platform/rt-thread/platform_internal.h +++ b/core/shared/platform/rt-thread/platform_internal.h @@ -124,7 +124,7 @@ typedef void *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index 1b870c70e..6a6b00f4b 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -101,7 +101,7 @@ os_sigreturn(); #define os_getpagesize getpagesize static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index 8bb77e7cb..8ff541016 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -6,6 +6,12 @@ #ifndef _PLATFORM_INTERNAL_H #define _PLATFORM_INTERNAL_H +/* + * Suppress the noisy warnings: + * winbase.h: warning C5105: macro expansion producing 'defined' has + * undefined behavior + */ +#pragma warning(disable : 5105) #include #include #include @@ -168,12 +174,13 @@ typedef struct windows_dir_stream { windows_handle *handle; } windows_dir_stream; -typedef windows_handle *os_file_handle; typedef windows_dir_stream *os_dir_stream; -#if WASM_ENABLE_UVWASI != 1 +#if WASM_ENABLE_UVWASI == 0 +typedef windows_handle *os_file_handle; typedef HANDLE os_raw_file_handle; #else +typedef uint32_t os_file_handle; typedef uint32_t os_raw_file_handle; #endif @@ -188,9 +195,13 @@ typedef uint32_t os_raw_file_handle; #endif static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { +#if WASM_ENABLE_UVWASI == 0 return NULL; +#else + return -1; +#endif } #ifdef __cplusplus diff --git a/core/shared/platform/windows/shared_platform.cmake b/core/shared/platform/windows/shared_platform.cmake index 502a8a2ed..c2d74463f 100644 --- a/core/shared/platform/windows/shared_platform.cmake +++ b/core/shared/platform/windows/shared_platform.cmake @@ -15,6 +15,9 @@ file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1) list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/win_file.c) +elseif (WAMR_BUILD_LIBC_UVWASI EQUAL 1) + # uvwasi doesn't need to compile win_file.c + list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/win_file.c) else() include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake) set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE}) diff --git a/core/shared/platform/windows/win_clock.c b/core/shared/platform/windows/win_clock.c index c96bdfb3b..ec0bc8566 100644 --- a/core/shared/platform/windows/win_clock.c +++ b/core/shared/platform/windows/win_clock.c @@ -10,6 +10,10 @@ #define NANOSECONDS_PER_SECOND 1000000000ULL #define NANOSECONDS_PER_TICK 100 +extern NTSTATUS +NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution, + PULONG CurrentResolution); + static __wasi_errno_t calculate_monotonic_clock_frequency(uint64 *out_frequency) { @@ -54,7 +58,7 @@ os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution) case __WASI_CLOCK_PROCESS_CPUTIME_ID: case __WASI_CLOCK_THREAD_CPUTIME_ID: { -#if WINAPI_PARTITION_DESKTOP +#if WINAPI_PARTITION_DESKTOP && WASM_ENABLE_WAMR_COMPILER == 0 ULONG maximum_time; ULONG minimum_time; ULONG current_time; @@ -140,4 +144,4 @@ os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, default: return __WASI_EINVAL; } -} \ No newline at end of file +} diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index b19e5b097..8d61c45cc 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -182,8 +182,8 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, (*sock)->type = windows_handle_type_socket; (*sock)->access_mode = windows_access_mode_read | windows_access_mode_write; (*sock)->fdflags = 0; - (*sock)->raw.socket = - accept(server_sock->raw.socket, (struct sockaddr *)&addr_tmp, &len); + (*sock)->raw.socket = accept(server_sock->raw.socket, + (struct sockaddr *)&addr_tmp, (int *)&len); if ((*sock)->raw.socket == INVALID_SOCKET) { BH_FREE(*sock); diff --git a/core/shared/platform/windows/win_util.h b/core/shared/platform/windows/win_util.h index 033c393b5..7fda508c7 100644 --- a/core/shared/platform/windows/win_util.h +++ b/core/shared/platform/windows/win_util.h @@ -7,7 +7,13 @@ #define _WIN_UTIL_H #include "platform_wasi_types.h" -#include "windows.h" +/* + * Suppress the noisy warnings: + * winbase.h: warning C5105: macro expansion producing 'defined' has + * undefined behavior + */ +#pragma warning(disable : 5105) +#include __wasi_timestamp_t convert_filetime_to_wasi_timestamp(LPFILETIME filetime); @@ -23,4 +29,4 @@ convert_windows_error_code(DWORD windows_error_code); __wasi_errno_t convert_winsock_error_code(int error_code); -#endif /* end of _WIN_UTIL_H */ \ No newline at end of file +#endif /* end of _WIN_UTIL_H */ diff --git a/core/shared/platform/zephyr/platform_internal.h b/core/shared/platform/zephyr/platform_internal.h index fa8fbd861..5bc9ca986 100644 --- a/core/shared/platform/zephyr/platform_internal.h +++ b/core/shared/platform/zephyr/platform_internal.h @@ -209,7 +209,7 @@ typedef void *os_dir_stream; typedef int os_raw_file_handle; static inline os_file_handle -os_get_invalid_handle() +os_get_invalid_handle(void) { return -1; } diff --git a/core/version.h b/core/version.h index 4e2cbaefc..4fe37e2d7 100644 --- a/core/version.h +++ b/core/version.h @@ -6,6 +6,6 @@ #ifndef _WAMR_VERSION_H_ #define _WAMR_VERSION_H_ #define WAMR_VERSION_MAJOR 2 -#define WAMR_VERSION_MINOR 1 -#define WAMR_VERSION_PATCH 2 +#define WAMR_VERSION_MINOR 2 +#define WAMR_VERSION_PATCH 0 #endif diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 2adb17f6a..4537ee084 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -300,6 +300,22 @@ Currently we only profile the memory consumption of module, module_instance and wasm_runtime_get_context ``` +#### **Shared heap among wasm apps and host native** +- **WAMR_BUILD_SHARED_HEAP**=1/0, default to disable if not set +> Note: If it is enabled, allow to create one or more shared heaps, and attach one to a module instance, the belows APIs ared provided: +```C + wasm_runtime_create_shared_heap + wasm_runtime_attach_shared_heap + wasm_runtime_detach_shared_heap + wasm_runtime_shared_heap_malloc + wasm_runtime_shared_heap_free +``` +And the wasm app can calls below APIs to allocate/free memory from/to the shared heap if it is attached to the app's module instance: +```C + void *shared_heap_malloc(); + void shared_heap_free(void *ptr); +``` + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/product-mini/platforms/common/libc_wasi.c b/product-mini/platforms/common/libc_wasi.c index 84e133bc0..2f0b35125 100644 --- a/product-mini/platforms/common/libc_wasi.c +++ b/product-mini/platforms/common/libc_wasi.c @@ -28,7 +28,7 @@ typedef enum { } libc_wasi_parse_result_t; static void -libc_wasi_print_help() +libc_wasi_print_help(void) { printf(" --env= Pass wasi environment variables with " "\"key=value\"\n"); diff --git a/product-mini/platforms/nuttx/CMakeLists.txt b/product-mini/platforms/nuttx/CMakeLists.txt index ac6c47b91..27ddd9fa9 100644 --- a/product-mini/platforms/nuttx/CMakeLists.txt +++ b/product-mini/platforms/nuttx/CMakeLists.txt @@ -49,6 +49,12 @@ else() add_definitions(-DWASM_ENABLE_WORD_ALIGN_READ=0) endif() +if(CONFIG_INTERPRETERS_WAMR_DYNAMIC_AOT_DEBUG) + add_definitions(-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1) +else() + add_definitions(-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=0) +endif() + if(CONFIG_INTERPRETERS_WAMR_STACK_GUARD_SIZE) add_definitions(-DWASM_STACK_GUARD_SIZE=0) else() @@ -197,7 +203,7 @@ include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) # NuttX wamr lib complie required: `WAMR_SOURCES` `WAMR_CFLAGS` `WAMR_INCDIRS` # `WAMR_DEFINITIONS` set(WAMR_SOURCES ${WAMR_RUNTIME_LIB_SOURCE}) -set(WAMR_CFLAGS -Wno-strict-prototypes -Wno-shadow -Wno-unused-variable +set(WAMR_CFLAGS -Wno-shadow -Wno-unused-variable -Wno-int-conversion -Wno-implicit-function-declaration) get_directory_property(WAMR_INCDIRS INCLUDE_DIRECTORIES) get_directory_property(WAMR_DEFINITIONS COMPILE_DEFINITIONS) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 38553e863..44d8694e5 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -148,6 +148,12 @@ else CFLAGS += -DWASM_ENABLE_WORD_ALIGN_READ=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_DYNAMIC_AOT_DEBUG),y) +CFLAGS += -DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1 +else +CFLAGS += -DWASM_ENABLE_DYNAMIC_AOT_DEBUG=0 +endif + ifeq ($(CONFIG_INTERPRETERS_WAMR_MEM_DUAL_BUS_MIRROR),y) CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=1 else @@ -400,7 +406,7 @@ CFLAGS += -DWASM_ENABLE_EXCE_HANDLING=0 CFLAGS += -DWASM_ENABLE_TAGS=0 endif -CFLAGS += -Wno-strict-prototypes -Wno-shadow -Wno-unused-variable +CFLAGS += -Wno-shadow -Wno-unused-variable CFLAGS += -Wno-int-conversion -Wno-implicit-function-declaration CFLAGS += -I${CORE_ROOT} \ diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index c1ba169d5..af50223a4 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -27,7 +27,7 @@ static char **app_argv; /* clang-format off */ static int -print_help() +print_help(void) { printf("Usage: iwasm [-options] wasm_file [args...]\n"); printf("options:\n"); @@ -928,6 +928,15 @@ main(int argc, char *argv[]) goto fail2; } +#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0 + if (!wasm_runtime_set_module_name(wasm_module, wasm_file, error_buf, + sizeof(error_buf))) { + printf("set aot module name failed in dynamic aot debug mode, %s\n", + error_buf); + goto fail3; + } +#endif + #if WASM_ENABLE_LIBC_WASI != 0 libc_wasi_init(wasm_module, argc, argv, &wasi_parse_ctx); #endif diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index 02aa3f31b..40e925b16 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -52,9 +52,9 @@ if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) set (WAMR_BUILD_LIBC_BUILTIN 1) endif () -if (NOT DEFINED WAMR_BUILD_LIBC_UVWASI) - # Enable libc uvwasi support by default - set (WAMR_BUILD_LIBC_UVWASI 1) +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 1) endif () if (NOT DEFINED WAMR_BUILD_FAST_INTERP) diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index f51c9dcc5..e85e869c2 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -45,6 +45,10 @@ print_help() #endif printf(" --stack-size=n Set maximum stack size in bytes, default is 64 KB\n"); printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); +#if WASM_ENABLE_GC != 0 + printf(" --gc-heap-size=n Set maximum gc heap size in bytes,\n"); + printf(" default is %u KB\n", GC_HEAP_SIZE_DEFAULT / 1024); +#endif #if WASM_ENABLE_JIT != 0 printf(" --llvm-jit-size-level=n Set LLVM JIT size level, default is 3\n"); printf(" --llvm-jit-opt-level=n Set LLVM JIT optimization level, default is 3\n"); @@ -271,6 +275,9 @@ main(int argc, char *argv[]) #else uint32 heap_size = 16 * 1024; #endif +#if WASM_ENABLE_GC != 0 + uint32 gc_heap_size = GC_HEAP_SIZE_DEFAULT; +#endif #if WASM_ENABLE_JIT != 0 uint32 llvm_jit_size_level = 3; uint32 llvm_jit_opt_level = 3; @@ -346,6 +353,13 @@ main(int argc, char *argv[]) return print_help(); heap_size = atoi(argv[0] + 12); } +#if WASM_ENABLE_GC != 0 + else if (!strncmp(argv[0], "--gc-heap-size=", 15)) { + if (argv[0][15] == '\0') + return print_help(); + gc_heap_size = atoi(argv[0] + 15); + } +#endif #if WASM_ENABLE_JIT != 0 else if (!strncmp(argv[0], "--llvm-jit-size-level=", 22)) { if (argv[0][22] == '\0') @@ -456,6 +470,10 @@ main(int argc, char *argv[]) init_args.mem_alloc_option.allocator.free_func = free_func; #endif +#if WASM_ENABLE_GC != 0 + init_args.gc_heap_size = gc_heap_size; +#endif + #if WASM_ENABLE_JIT != 0 init_args.llvm_jit_size_level = llvm_jit_size_level; init_args.llvm_jit_opt_level = llvm_jit_opt_level; diff --git a/samples/gui/wasm-apps/decrease/src/main.c b/samples/gui/wasm-apps/decrease/src/main.c deleted file mode 100644 index 9635ebea8..000000000 --- a/samples/gui/wasm-apps/decrease/src/main.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include "wasm_app.h" -#include "wa-inc/lvgl/lvgl.h" -#include "wa-inc/timer_wasm_app.h" - -extern char g_widget_text[]; - -static void -btn_event_cb(lv_obj_t *btn, lv_event_t event); - -uint32_t count = 0; -char count_str[11] = { 0 }; -lv_obj_t *hello_world_label; -lv_obj_t *count_label; -lv_obj_t *btn1; -lv_obj_t *label_count1; -int label_count1_value = 100; -char label_count1_str[11] = { 0 }; - -void -timer1_update(user_timer_t timer1) -{ - if ((count % 100) == 0) { - snprintf(count_str, sizeof(count_str), "%d", count / 100); - lv_label_set_text(count_label, count_str); - } - ++count; -} - -void -on_init() -{ - char *text; - - hello_world_label = lv_label_create(NULL, NULL); - lv_label_set_text(hello_world_label, "Hello world!"); - text = lv_label_get_text(hello_world_label); - printf("Label text %lu %s \n", strlen(text), text); - lv_obj_align(hello_world_label, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); - - count_label = lv_label_create(NULL, NULL); - lv_obj_align(count_label, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); - - /* Create a button on the currently loaded screen */ - btn1 = lv_btn_create(NULL, NULL); - /* Set function to be called when the button is released */ - lv_obj_set_event_cb(btn1, (lv_event_cb_t)btn_event_cb); - /* Align below the label */ - lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, 0); - - /* Create a label on the button */ - lv_obj_t *btn_label = lv_label_create(btn1, NULL); - lv_label_set_text(btn_label, "Click --"); - - label_count1 = lv_label_create(NULL, NULL); - lv_label_set_text(label_count1, "100"); - lv_obj_align(label_count1, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); - - /* Set up a timer */ - user_timer_t timer; - timer = api_timer_create(10, true, false, timer1_update); - if (timer) - api_timer_restart(timer, 10); - else - printf("Fail to create timer.\n"); -} - -static void -btn_event_cb(lv_obj_t *btn, lv_event_t event) -{ - if (event == LV_EVENT_RELEASED) { - label_count1_value--; - snprintf(label_count1_str, sizeof(label_count1_str), "%d", - label_count1_value); - lv_label_set_text(label_count1, label_count1_str); - if (label_count1_value == 0) - label_count1_value = 100; - } -} diff --git a/samples/gui/wasm-apps/increase/src/main.c b/samples/gui/wasm-apps/increase/src/main.c deleted file mode 100644 index 31118f7be..000000000 --- a/samples/gui/wasm-apps/increase/src/main.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include "wasm_app.h" -#include "wa-inc/lvgl/lvgl.h" -#include "wa-inc/timer_wasm_app.h" - -extern char g_widget_text[]; - -static void -btn_event_cb(lv_obj_t *btn, lv_event_t event); - -uint32_t count = 0; -char count_str[11] = { 0 }; -lv_obj_t *hello_world_label; -lv_obj_t *count_label; -lv_obj_t *btn1; -lv_obj_t *label_count1; -int label_count1_value = 1; -char label_count1_str[11] = { 0 }; - -void -timer1_update(user_timer_t timer1) -{ - if ((count % 100) == 0) { - snprintf(count_str, sizeof(count_str), "%d", count / 100); - lv_label_set_text(count_label, count_str); - } - ++count; -} - -void -on_init() -{ - char *text; - - hello_world_label = lv_label_create(NULL, NULL); - lv_label_set_text(hello_world_label, "Hello world!"); - text = lv_label_get_text(hello_world_label); - printf("Label text %lu %s \n", strlen(text), text); - lv_obj_align(hello_world_label, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); - - count_label = lv_label_create(NULL, NULL); - lv_obj_align(count_label, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); - - /* Create a button on the current loaded screen */ - btn1 = lv_btn_create(NULL, NULL); - /* Set function to be called when the button is released */ - lv_obj_set_event_cb(btn1, (lv_event_cb_t)btn_event_cb); - /* Align below the label */ - lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, 0); - - /* Create a label on the button */ - lv_obj_t *btn_label = lv_label_create(btn1, NULL); - lv_label_set_text(btn_label, "Click ++"); - - label_count1 = lv_label_create(NULL, NULL); - lv_label_set_text(label_count1, "1"); - lv_obj_align(label_count1, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); - - /* Set up a timer */ - user_timer_t timer; - timer = api_timer_create(10, true, false, timer1_update); - if (timer) - api_timer_restart(timer, 10); - else - printf("Fail to create timer.\n"); -} - -static void -btn_event_cb(lv_obj_t *btn, lv_event_t event) -{ - if (event == LV_EVENT_RELEASED) { - label_count1_value++; - snprintf(label_count1_str, sizeof(label_count1_str), "%d", - label_count1_value); - lv_label_set_text(label_count1, label_count1_str); - if (label_count1_value == 100) - label_count1_value = 0; - } -} diff --git a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c deleted file mode 100644 index 5502cfd89..000000000 --- a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c +++ /dev/null @@ -1,348 +0,0 @@ -/** - * @file XPT2046.c - */ -/********************* - * INCLUDES - *********************/ -#include "XPT2046.h" -#include "board_config.h" -#include "stdio.h" -#include -#include "drivers/spi.h" - -#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ -#include -#include -#else -#include -#endif - -#if USE_XPT2046 - -#include - -#define abs(x) ((x) < 0 ? -(x) : (x)) - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static void -xpt2046_corr(int16_t *x, int16_t *y); -#if 0 -static void xpt2046_avg(int16_t * x, int16_t * y); -#endif - -/********************** - * STATIC VARIABLES - **********************/ -int16_t avg_buf_x[XPT2046_AVG]; -int16_t avg_buf_y[XPT2046_AVG]; -uint8_t avg_last; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the XPT2046 - */ -struct device *input_dev; - -struct spi_config spi_conf_xpt2046; -struct spi_cs_control xpt2046_cs_ctrl; -struct device *xpt2046_pen_gpio_dev; -static struct gpio_callback gpio_cb; -lv_indev_data_t touch_point; -lv_indev_data_t last_touch_point; - -#define TOUCH_READ_THREAD_STACK_SIZE 4096 -static K_THREAD_STACK_DEFINE(touch_read_thread_stack, - TOUCH_READ_THREAD_STACK_SIZE); -static struct k_thread touch_thread_data; -static struct k_sem sem_touch_read; - -K_MUTEX_DEFINE(spi_display_touch_mutex); - -int cnt = 0; -int touch_read_times = 0; -int last_pen_interrupt_time = 0; -void -xpt2046_pen_gpio_callback(struct device *port, struct gpio_callback *cb, - u32_t pins) -{ - cnt++; - if ((k_uptime_get_32() - last_pen_interrupt_time) > 500) { - k_sem_give(&sem_touch_read); - touch_read_times++; - last_pen_interrupt_time = k_uptime_get_32(); - } -} - -void -disable_pen_interrupt() -{ - int ret = 0; - ret = gpio_disable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); - if (ret != 0) { - printf("gpio_pin_configure GPIO_INPUT failed\n"); - } -} -void -enable_pen_interrupt() -{ - int ret = 0; - ret = gpio_enable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); - if (ret != 0) { - printf("gpio_pin_configure failed\n"); - } -} - -void -touch_screen_read_thread() -{ - int i; - bool ret = false; - - for (;;) { - k_sem_take(&sem_touch_read, K_FOREVER); - memset(&last_touch_point, 0, sizeof(lv_indev_data_t)); - memset(&touch_point, 0, sizeof(lv_indev_data_t)); - memset(avg_buf_x, 0, sizeof(avg_buf_x)); - memset(avg_buf_y, 0, sizeof(avg_buf_y)); - k_mutex_lock(&spi_display_touch_mutex, K_FOREVER); - disable_pen_interrupt(); - for (i = 0; i < 100; i++) { - ret = xpt2046_read(&touch_point); - if (ret) { - if ((abs(last_touch_point.point.x - touch_point.point.x) < 4) - && (abs(last_touch_point.point.y - touch_point.point.y) - < 4)) { - break; - } - last_touch_point = touch_point; - } - } - enable_pen_interrupt(); - k_mutex_unlock(&spi_display_touch_mutex); - } -} - -void -xpt2046_init(void) -{ - int ret; - input_dev = device_get_binding(XPT2046_SPI_DEVICE_NAME); - - if (input_dev == NULL) { - printf("device not found. Aborting test."); - return; - } - memset((void *)&touch_point, 0, sizeof(lv_indev_data_t)); - - spi_conf_xpt2046.frequency = XPT2046_SPI_MAX_FREQUENCY; - spi_conf_xpt2046.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8); - spi_conf_xpt2046.slave = 0; - spi_conf_xpt2046.cs = NULL; -#ifdef XPT2046_CS_GPIO_CONTROLLER - xpt2046_cs_ctrl.gpio_dev = device_get_binding(XPT2046_CS_GPIO_CONTROLLER); - if (xpt2046_cs_ctrl.gpio_dev == NULL) { - printk("Cannot find %s!\n", XPT2046_CS_GPIO_CONTROLLER); - return; - } - gpio_pin_configure(xpt2046_cs_ctrl.gpio_dev, XPT2046_CS_GPIO_PIN, - GPIO_OUTPUT); - gpio_pin_set(xpt2046_cs_ctrl.gpio_dev, XPT2046_CS_GPIO_PIN, 1); - xpt2046_cs_ctrl.gpio_pin = XPT2046_CS_GPIO_PIN; - xpt2046_cs_ctrl.delay = 0; - spi_conf_xpt2046.cs = &xpt2046_cs_ctrl; - -#endif - -#ifdef XPT2046_PEN_GPIO_CONTROLLER - - xpt2046_pen_gpio_dev = device_get_binding(XPT2046_PEN_GPIO_CONTROLLER); - if (!xpt2046_pen_gpio_dev) { - printk("Cannot find %s!\n", XPT2046_PEN_GPIO_CONTROLLER); - return; - } - /* Setup GPIO input */ - ret = gpio_pin_configure(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN, - (GPIO_INPUT | GPIO_INT_ENABLE | GPIO_INT_EDGE - | GPIO_INT_LOW_0 | GPIO_INT_DEBOUNCE)); - if (ret) { - printk("Error configuring pin %d!\n", XPT2046_PEN_GPIO_PIN); - } - - gpio_init_callback(&gpio_cb, xpt2046_pen_gpio_callback, - BIT(XPT2046_PEN_GPIO_PIN)); - - ret = gpio_add_callback(xpt2046_pen_gpio_dev, &gpio_cb); - if (ret) { - printk("gpio_add_callback error\n"); - } - ret = gpio_enable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); - if (ret) { - printk("gpio_enable_callback error\n"); - } -#endif - - k_sem_init(&sem_touch_read, 0, 1); - - k_thread_create(&touch_thread_data, touch_read_thread_stack, - TOUCH_READ_THREAD_STACK_SIZE, touch_screen_read_thread, - NULL, NULL, NULL, 5, 0, K_NO_WAIT); - printf("xpt2046_init ok \n"); -} - -/** - * Get the current position and state of the touchpad - * @param data store the read data here - * @return false: because no ore data to be read - */ -bool -xpt2046_read(lv_indev_data_t *data) -{ - static int16_t last_x = 0; - static int16_t last_y = 0; - bool valid = true; - int s32_ret = 0; - - int16_t x = 0; - int16_t y = 0; - - char tx1[16] = { 0 }; - char rx1[16] = { 0 }; - - struct spi_buf tx_buf = { .buf = &tx1, .len = 3 }; - struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; - struct spi_buf rx_buf = { .buf = &rx1, .len = 3 }; - struct spi_buf_set rx_bufs = { .buffers = &rx_buf, .count = 1 }; - - tx1[0] = CMD_X_READ; - s32_ret = spi_transceive(input_dev, &spi_conf_xpt2046, &tx_bufs, &rx_bufs); - if (s32_ret != 0) { - printf("spi_transceive return failed:%d\n", s32_ret); - } - x = rx1[1] << 8; - x += rx1[2]; - - tx1[0] = CMD_Y_READ; - s32_ret = spi_transceive(input_dev, &spi_conf_xpt2046, &tx_bufs, &rx_bufs); - if (s32_ret != 0) { - printf("spi_transceive return failed:%d\n", s32_ret); - } - y = rx1[1] << 8; - y += rx1[2]; - x = x >> 3; - y = y >> 3; - - xpt2046_corr(&x, &y); - if (y <= 0 || (x > 320)) { - valid = false; - } - - last_x = x; - last_y = y; - - data->point.x = x; - data->point.y = y; - data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; - - return valid; -} - -/********************** - * STATIC FUNCTIONS - **********************/ -static void -xpt2046_corr(int16_t *x, int16_t *y) -{ -#if XPT2046_XY_SWAP != 0 - int16_t swap_tmp; - swap_tmp = *x; - *x = *y; - *y = swap_tmp; -#endif - - if ((*x) > XPT2046_X_MIN) - (*x) -= XPT2046_X_MIN; - else - (*x) = 0; - - if ((*y) > XPT2046_Y_MIN) - (*y) -= XPT2046_Y_MIN; - else - (*y) = 0; - - (*x) = (uint32_t)((uint32_t)(*x) * XPT2046_HOR_RES) - / (XPT2046_X_MAX - XPT2046_X_MIN); - - (*y) = (uint32_t)((uint32_t)(*y) * XPT2046_VER_RES) - / (XPT2046_Y_MAX - XPT2046_Y_MIN); - -#if XPT2046_X_INV != 0 - (*x) = XPT2046_HOR_RES - (*x); -#endif - -#if XPT2046_Y_INV != 0 - (*y) = XPT2046_VER_RES - (*y); -#endif -} - -#if 0 -static void xpt2046_avg(int16_t * x, int16_t * y) -{ - /*Shift out the oldest data*/ - uint8_t i; - for (i = XPT2046_AVG - 1; i > 0; i--) { - avg_buf_x[i] = avg_buf_x[i - 1]; - avg_buf_y[i] = avg_buf_y[i - 1]; - } - - /*Insert the new point*/ - avg_buf_x[0] = *x; - avg_buf_y[0] = *y; - if (avg_last < XPT2046_AVG) - avg_last++; - - /*Sum the x and y coordinates*/ - int32_t x_sum = 0; - int32_t y_sum = 0; - for (i = 0; i < avg_last; i++) { - x_sum += avg_buf_x[i]; - y_sum += avg_buf_y[i]; - } - - /*Normalize the sums*/ - (*x) = (int32_t) x_sum / avg_last; - (*y) = (int32_t) y_sum / avg_last; -} -#endif - -bool -touchscreen_read(lv_indev_data_t *data) -{ - /*Store the collected data*/ - data->point.x = last_touch_point.point.x; - data->point.y = last_touch_point.point.y; - data->state = last_touch_point.state; - - if (last_touch_point.state == LV_INDEV_STATE_PR) { - last_touch_point.state = LV_INDEV_STATE_REL; - } - return false; -} - -#endif diff --git a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h deleted file mode 100644 index ddc396e1d..000000000 --- a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2017 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ -#define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ -#include "board_config.h" -#include - -#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ -#include -#else -#include -#endif - -#define ILI9340_CMD_ENTER_SLEEP 0x10 -#define ILI9340_CMD_EXIT_SLEEP 0x11 -#define ILI9340_CMD_GAMMA_SET 0x26 -#define ILI9340_CMD_DISPLAY_OFF 0x28 -#define ILI9340_CMD_DISPLAY_ON 0x29 -#define ILI9340_CMD_COLUMN_ADDR 0x2a -#define ILI9340_CMD_PAGE_ADDR 0x2b -#define ILI9340_CMD_MEM_WRITE 0x2c -#define ILI9340_CMD_MEM_ACCESS_CTRL 0x36 -#define ILI9340_CMD_PIXEL_FORMAT_SET 0x3A -#define ILI9340_CMD_FRAME_CTRL_NORMAL_MODE 0xB1 -#define ILI9340_CMD_DISPLAY_FUNCTION_CTRL 0xB6 -#define ILI9340_CMD_POWER_CTRL_1 0xC0 -#define ILI9340_CMD_POWER_CTRL_2 0xC1 -#define ILI9340_CMD_VCOM_CTRL_1 0xC5 -#define ILI9340_CMD_VCOM_CTRL_2 0xC7 -#define ILI9340_CMD_POSITVE_GAMMA_CORRECTION 0xE0 -#define ILI9340_CMD_NEGATIVE_GAMMA_CORRECTION 0xE1 - -#define ILI9340_DATA_MEM_ACCESS_CTRL_MY 0x80 -#define ILI9340_DATA_MEM_ACCESS_CTRL_MX 0x40 -#define ILI9340_DATA_MEM_ACCESS_CTRL_MV 0x20 -#define ILI9340_DATA_MEM_ACCESS_CTRL_ML 0x10 -#define ILI9340_DATA_MEM_ACCESS_CTRL_BGR 0x08 -#define ILI9340_DATA_MEM_ACCESS_CTRL_MH 0x04 - -#define ILI9340_DATA_PIXEL_FORMAT_RGB_18_BIT 0x60 -#define ILI9340_DATA_PIXEL_FORMAT_RGB_16_BIT 0x50 -#define ILI9340_DATA_PIXEL_FORMAT_MCU_18_BIT 0x06 -#define ILI9340_DATA_PIXEL_FORMAT_MCU_16_BIT 0x05 - -struct ili9340_data; - -/** - * Send data to ILI9340 display controller - * - * @param data Device data structure - * @param cmd Command to send to display controller - * @param tx_data Data to transmit to the display controller - * In case no data should be transmitted pass a NULL pointer - * @param tx_len Number of bytes in tx_data buffer - * - */ -void -ili9340_transmit(struct ili9340_data *data, u8_t cmd, void *tx_data, - size_t tx_len); - -/** - * Perform LCD specific initialization - * - * @param data Device data structure - */ -void -ili9340_lcd_init(struct ili9340_data *data); - -#define DT_ILITEK_ILI9340_0_LABEL "DISPLAY" -#define CONFIG_DISPLAY_LOG_LEVEL 0 - -#endif /* ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ */ diff --git a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c deleted file mode 100644 index 9ce0c11cd..000000000 --- a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ -#include "bh_platform.h" -#include "runtime_lib.h" -#include "native_interface.h" -#include "app_manager_export.h" -#include "board_config.h" -#include "bh_common.h" -#include "bh_queue.h" -#include "runtime_sensor.h" -#include "bi-inc/attr_container.h" -#include "module_wasm_app.h" -#include "wasm_export.h" -#include "display.h" -#include "lvgl.h" - -extern bool -init_sensor_framework(); -extern void -exit_sensor_framework(); -extern int -aee_host_msg_callback(void *msg, uint32_t msg_len); -extern bool -touchscreen_read(lv_indev_data_t *data); -extern int -ili9340_init(); -extern void -xpt2046_init(void); -extern void -wgl_init(); - -#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ -#include -#else -#include -#endif - -#include -#include - -int uart_char_cnt = 0; - -static void -uart_irq_callback(struct device *dev) -{ - unsigned char ch; - - while (uart_poll_in(dev, &ch) == 0) { - uart_char_cnt++; - aee_host_msg_callback(&ch, 1); - } -} - -struct device *uart_dev = NULL; - -static bool -host_init() -{ - uart_dev = device_get_binding(HOST_DEVICE_COMM_UART_NAME); - if (!uart_dev) { - printf("UART: Device driver not found.\n"); - return false; - } - uart_irq_rx_enable(uart_dev); - uart_irq_callback_set(uart_dev, uart_irq_callback); - return true; -} - -int -host_send(void *ctx, const char *buf, int size) -{ - if (!uart_dev) - return 0; - - for (int i = 0; i < size; i++) - uart_poll_out(uart_dev, buf[i]); - - return size; -} - -void -host_destroy() -{} - -/* clang-format off */ -host_interface interface = { - .init = host_init, - .send = host_send, - .destroy = host_destroy -}; -/* clang-format on */ - -timer_ctx_t timer_ctx; - -static char global_heap_buf[270 * 1024] = { 0 }; - -static uint8_t color_copy[320 * 10 * 3]; - -static void -display_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color) -{ - u16_t w = area->x2 - area->x1 + 1; - u16_t h = area->y2 - area->y1 + 1; - struct display_buffer_descriptor desc; - int i; - uint8_t *color_p = color_copy; - - desc.buf_size = 3 * w * h; - desc.width = w; - desc.pitch = w; - desc.height = h; - - for (i = 0; i < w * h; i++, color++) { - color_p[i * 3] = color->ch.red; - color_p[i * 3 + 1] = color->ch.green; - color_p[i * 3 + 2] = color->ch.blue; - } - - display_write(NULL, area->x1, area->y1, &desc, (void *)color_p); - - lv_disp_flush_ready(disp_drv); /* in v5.3 is lv_flush_ready */ -} - -static bool -display_input_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) -{ - return touchscreen_read(data); -} - -/** - * Initialize the Hardware Abstraction Layer (HAL) for the Littlev graphics - * library - */ -static void -hal_init(void) -{ - xpt2046_init(); - ili9340_init(); - display_blanking_off(NULL); - - /*Create a display buffer*/ - static lv_disp_buf_t disp_buf1; - static lv_color_t buf1_1[320 * 10]; - lv_disp_buf_init(&disp_buf1, buf1_1, NULL, 320 * 10); - - /*Create a display*/ - lv_disp_drv_t disp_drv; - lv_disp_drv_init(&disp_drv); /*Basic initialization*/ - disp_drv.buffer = &disp_buf1; - disp_drv.flush_cb = display_flush; - // disp_drv.hor_res = 200; - // disp_drv.ver_res = 100; - lv_disp_drv_register(&disp_drv); - - lv_indev_drv_t indev_drv; - lv_indev_drv_init(&indev_drv); /*Basic initialization*/ - indev_drv.type = LV_INDEV_TYPE_POINTER; - indev_drv.read_cb = display_input_read; - lv_indev_drv_register(&indev_drv); -} - -int -iwasm_main() -{ - RuntimeInitArgs init_args; - host_init(); - - memset(&init_args, 0, sizeof(RuntimeInitArgs)); - - init_args.mem_alloc_type = Alloc_With_Pool; - init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; - init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); - - /* initialize runtime environment */ - if (!wasm_runtime_full_init(&init_args)) { - printf("Init runtime environment failed.\n"); - return -1; - } - - wgl_init(); - hal_init(); - - /* timer manager */ - if (!init_wasm_timer()) { - goto fail; - } - - app_manager_startup(&interface); - -fail: - wasm_runtime_destroy(); - return -1; -} diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c deleted file mode 100644 index e3948e2f2..000000000 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c +++ /dev/null @@ -1,349 +0,0 @@ -/** - * @file XPT2046.c - */ -/********************* - * INCLUDES - *********************/ -#include "XPT2046.h" -#include "board_config.h" -#include "stdio.h" -#include -#include "drivers/spi.h" - -#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ -#include -#include -#else -#include -#endif - -#if USE_XPT2046 - -#include - -#define abs(x) ((x) < 0 ? -(x) : (x)) - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static void -xpt2046_corr(int16_t *x, int16_t *y); -#if 0 -static void xpt2046_avg(int16_t * x, int16_t * y); -#endif - -/********************** - * STATIC VARIABLES - **********************/ -int16_t avg_buf_x[XPT2046_AVG]; -int16_t avg_buf_y[XPT2046_AVG]; -uint8_t avg_last; - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Initialize the XPT2046 - */ -struct device *input_dev; - -struct spi_config spi_conf_xpt2046; -struct spi_cs_control xpt2046_cs_ctrl; -struct device *xpt2046_pen_gpio_dev; -static struct gpio_callback gpio_cb; -lv_indev_data_t touch_point; -lv_indev_data_t last_touch_point; - -#define TOUCH_READ_THREAD_STACK_SIZE 4096 -static K_THREAD_STACK_DEFINE(touch_read_thread_stack, - TOUCH_READ_THREAD_STACK_SIZE); -static struct k_thread touch_thread_data; -static struct k_sem sem_touch_read; - -K_MUTEX_DEFINE(spi_display_touch_mutex); - -int cnt = 0; -int touch_read_times = 0; -int last_pen_interrupt_time = 0; - -void -xpt2046_pen_gpio_callback(struct device *port, struct gpio_callback *cb, - uint32_t pins) -{ - cnt++; - if ((k_uptime_get_32() - last_pen_interrupt_time) > 500) { - k_sem_give(&sem_touch_read); - touch_read_times++; - last_pen_interrupt_time = k_uptime_get_32(); - } -} - -void -disable_pen_interrupt() -{ - int ret = 0; - ret = gpio_disable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); - if (ret != 0) { - printf("gpio_pin_configure GPIO_INPUT failed\n"); - } -} -void -enable_pen_interrupt() -{ - int ret = 0; - ret = gpio_enable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); - if (ret != 0) { - printf("gpio_pin_configure failed\n"); - } -} - -void -touch_screen_read_thread() -{ - int i; - bool ret = false; - - for (;;) { - k_sem_take(&sem_touch_read, K_FOREVER); - memset(&last_touch_point, 0, sizeof(lv_indev_data_t)); - memset(&touch_point, 0, sizeof(lv_indev_data_t)); - memset(avg_buf_x, 0, sizeof(avg_buf_x)); - memset(avg_buf_y, 0, sizeof(avg_buf_y)); - k_mutex_lock(&spi_display_touch_mutex, K_FOREVER); - disable_pen_interrupt(); - for (i = 0; i < 100; i++) { - ret = xpt2046_read(&touch_point); - if (ret) { - if ((abs(last_touch_point.point.x - touch_point.point.x) < 4) - && (abs(last_touch_point.point.y - touch_point.point.y) - < 4)) { - break; - } - last_touch_point = touch_point; - } - } - enable_pen_interrupt(); - k_mutex_unlock(&spi_display_touch_mutex); - } -} - -void -xpt2046_init(void) -{ - int ret; - input_dev = device_get_binding(XPT2046_SPI_DEVICE_NAME); - - if (input_dev == NULL) { - printf("device not found. Aborting test."); - return; - } - memset((void *)&touch_point, 0, sizeof(lv_indev_data_t)); - - spi_conf_xpt2046.frequency = XPT2046_SPI_MAX_FREQUENCY; - spi_conf_xpt2046.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8); - spi_conf_xpt2046.slave = 0; - spi_conf_xpt2046.cs = NULL; -#ifdef XPT2046_CS_GPIO_CONTROLLER - xpt2046_cs_ctrl.gpio_dev = device_get_binding(XPT2046_CS_GPIO_CONTROLLER); - if (xpt2046_cs_ctrl.gpio_dev == NULL) { - printk("Cannot find %s!\n", XPT2046_CS_GPIO_CONTROLLER); - return; - } - gpio_pin_configure(xpt2046_cs_ctrl.gpio_dev, XPT2046_CS_GPIO_PIN, - GPIO_OUTPUT); - gpio_pin_set(xpt2046_cs_ctrl.gpio_dev, XPT2046_CS_GPIO_PIN, 1); - xpt2046_cs_ctrl.gpio_pin = XPT2046_CS_GPIO_PIN; - xpt2046_cs_ctrl.delay = 0; - spi_conf_xpt2046.cs = &xpt2046_cs_ctrl; - -#endif - -#ifdef XPT2046_PEN_GPIO_CONTROLLER - - xpt2046_pen_gpio_dev = device_get_binding(XPT2046_PEN_GPIO_CONTROLLER); - if (!xpt2046_pen_gpio_dev) { - printk("Cannot find %s!\n", XPT2046_PEN_GPIO_CONTROLLER); - return; - } - /* Setup GPIO input */ - ret = gpio_pin_configure(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN, - (GPIO_INPUT | GPIO_INT_ENABLE | GPIO_INT_EDGE - | GPIO_INT_LOW_0 | GPIO_INT_DEBOUNCE)); - if (ret) { - printk("Error configuring pin %d!\n", XPT2046_PEN_GPIO_PIN); - } - - gpio_init_callback(&gpio_cb, xpt2046_pen_gpio_callback, - BIT(XPT2046_PEN_GPIO_PIN)); - - ret = gpio_add_callback(xpt2046_pen_gpio_dev, &gpio_cb); - if (ret) { - printk("gpio_add_callback error\n"); - } - ret = gpio_enable_callback(xpt2046_pen_gpio_dev, XPT2046_PEN_GPIO_PIN); - if (ret) { - printk("gpio_enable_callback error\n"); - } -#endif - - k_sem_init(&sem_touch_read, 0, 1); - - k_thread_create(&touch_thread_data, touch_read_thread_stack, - TOUCH_READ_THREAD_STACK_SIZE, touch_screen_read_thread, - NULL, NULL, NULL, 5, 0, K_NO_WAIT); - printf("xpt2046_init ok \n"); -} - -/** - * Get the current position and state of the touchpad - * @param data store the read data here - * @return false: because no ore data to be read - */ -bool -xpt2046_read(lv_indev_data_t *data) -{ - static int16_t last_x = 0; - static int16_t last_y = 0; - bool valid = true; - int s32_ret = 0; - - int16_t x = 0; - int16_t y = 0; - - char tx1[16] = { 0 }; - char rx1[16] = { 0 }; - - struct spi_buf tx_buf = { .buf = &tx1, .len = 3 }; - struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; - struct spi_buf rx_buf = { .buf = &rx1, .len = 3 }; - struct spi_buf_set rx_bufs = { .buffers = &rx_buf, .count = 1 }; - - tx1[0] = CMD_X_READ; - s32_ret = spi_transceive(input_dev, &spi_conf_xpt2046, &tx_bufs, &rx_bufs); - if (s32_ret != 0) { - printf("spi_transceive return failed:%d\n", s32_ret); - } - x = rx1[1] << 8; - x += rx1[2]; - - tx1[0] = CMD_Y_READ; - s32_ret = spi_transceive(input_dev, &spi_conf_xpt2046, &tx_bufs, &rx_bufs); - if (s32_ret != 0) { - printf("spi_transceive return failed:%d\n", s32_ret); - } - y = rx1[1] << 8; - y += rx1[2]; - x = x >> 3; - y = y >> 3; - - xpt2046_corr(&x, &y); - if (y <= 0 || (x > 320)) { - valid = false; - } - - last_x = x; - last_y = y; - - data->point.x = x; - data->point.y = y; - data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; - - return valid; -} - -/********************** - * STATIC FUNCTIONS - **********************/ -static void -xpt2046_corr(int16_t *x, int16_t *y) -{ -#if XPT2046_XY_SWAP != 0 - int16_t swap_tmp; - swap_tmp = *x; - *x = *y; - *y = swap_tmp; -#endif - - if ((*x) > XPT2046_X_MIN) - (*x) -= XPT2046_X_MIN; - else - (*x) = 0; - - if ((*y) > XPT2046_Y_MIN) - (*y) -= XPT2046_Y_MIN; - else - (*y) = 0; - - (*x) = (uint32_t)((uint32_t)(*x) * XPT2046_HOR_RES) - / (XPT2046_X_MAX - XPT2046_X_MIN); - - (*y) = (uint32_t)((uint32_t)(*y) * XPT2046_VER_RES) - / (XPT2046_Y_MAX - XPT2046_Y_MIN); - -#if XPT2046_X_INV != 0 - (*x) = XPT2046_HOR_RES - (*x); -#endif - -#if XPT2046_Y_INV != 0 - (*y) = XPT2046_VER_RES - (*y); -#endif -} - -#if 0 -static void xpt2046_avg(int16_t * x, int16_t * y) -{ - /*Shift out the oldest data*/ - uint8_t i; - for (i = XPT2046_AVG - 1; i > 0; i--) { - avg_buf_x[i] = avg_buf_x[i - 1]; - avg_buf_y[i] = avg_buf_y[i - 1]; - } - - /*Insert the new point*/ - avg_buf_x[0] = *x; - avg_buf_y[0] = *y; - if (avg_last < XPT2046_AVG) - avg_last++; - - /*Sum the x and y coordinates*/ - int32_t x_sum = 0; - int32_t y_sum = 0; - for (i = 0; i < avg_last; i++) { - x_sum += avg_buf_x[i]; - y_sum += avg_buf_y[i]; - } - - /*Normalize the sums*/ - (*x) = (int32_t) x_sum / avg_last; - (*y) = (int32_t) y_sum / avg_last; -} -#endif - -bool -touchscreen_read(lv_indev_data_t *data) -{ - /*Store the collected data*/ - data->point.x = last_touch_point.point.x; - data->point.y = last_touch_point.point.y; - data->state = last_touch_point.state; - - if (last_touch_point.state == LV_INDEV_STATE_PR) { - last_touch_point.state = LV_INDEV_STATE_REL; - } - return false; -} - -#endif diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h deleted file mode 100644 index 39257a29a..000000000 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2017 Jan Van Winkel - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ -#define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ -#include "board_config.h" -#include - -#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ -#include -#else -#include -#endif - -#define ILI9340_CMD_ENTER_SLEEP 0x10 -#define ILI9340_CMD_EXIT_SLEEP 0x11 -#define ILI9340_CMD_GAMMA_SET 0x26 -#define ILI9340_CMD_DISPLAY_OFF 0x28 -#define ILI9340_CMD_DISPLAY_ON 0x29 -#define ILI9340_CMD_COLUMN_ADDR 0x2a -#define ILI9340_CMD_PAGE_ADDR 0x2b -#define ILI9340_CMD_MEM_WRITE 0x2c -#define ILI9340_CMD_MEM_ACCESS_CTRL 0x36 -#define ILI9340_CMD_PIXEL_FORMAT_SET 0x3A -#define ILI9340_CMD_FRAME_CTRL_NORMAL_MODE 0xB1 -#define ILI9340_CMD_DISPLAY_FUNCTION_CTRL 0xB6 -#define ILI9340_CMD_POWER_CTRL_1 0xC0 -#define ILI9340_CMD_POWER_CTRL_2 0xC1 -#define ILI9340_CMD_VCOM_CTRL_1 0xC5 -#define ILI9340_CMD_VCOM_CTRL_2 0xC7 -#define ILI9340_CMD_POSITVE_GAMMA_CORRECTION 0xE0 -#define ILI9340_CMD_NEGATIVE_GAMMA_CORRECTION 0xE1 - -#define ILI9340_DATA_MEM_ACCESS_CTRL_MY 0x80 -#define ILI9340_DATA_MEM_ACCESS_CTRL_MX 0x40 -#define ILI9340_DATA_MEM_ACCESS_CTRL_MV 0x20 -#define ILI9340_DATA_MEM_ACCESS_CTRL_ML 0x10 -#define ILI9340_DATA_MEM_ACCESS_CTRL_BGR 0x08 -#define ILI9340_DATA_MEM_ACCESS_CTRL_MH 0x04 - -#define ILI9340_DATA_PIXEL_FORMAT_RGB_18_BIT 0x60 -#define ILI9340_DATA_PIXEL_FORMAT_RGB_16_BIT 0x50 -#define ILI9340_DATA_PIXEL_FORMAT_MCU_18_BIT 0x06 -#define ILI9340_DATA_PIXEL_FORMAT_MCU_16_BIT 0x05 - -struct ili9340_data; - -/** - * Send data to ILI9340 display controller - * - * @param data Device data structure - * @param cmd Command to send to display controller - * @param tx_data Data to transmit to the display controller - * In case no data should be transmitted pass a NULL pointer - * @param tx_len Number of bytes in tx_data buffer - * - */ -void -ili9340_transmit(struct ili9340_data *data, uint8_t cmd, void *tx_data, - size_t tx_len); - -/** - * Perform LCD specific initialization - * - * @param data Device data structure - */ -void -ili9340_lcd_init(struct ili9340_data *data); - -#define DT_ILITEK_ILI9340_0_LABEL "DISPLAY" -#define CONFIG_DISPLAY_LOG_LEVEL 0 - -#endif /* ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ */ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c deleted file mode 100644 index 10f498026..000000000 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ -#include "bh_platform.h" -#include "runtime_lib.h" -#include "native_interface.h" -#include "app_manager_export.h" -#include "board_config.h" -#include "bh_platform.h" -#include "runtime_sensor.h" -#include "bi-inc/attr_container.h" -#include "module_wasm_app.h" -#include "wasm_export.h" -#include "sensor_native_api.h" -#include "connection_native_api.h" -#include "display_indev.h" - -#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ -#include -#else -#include -#endif - -#include -#include - -extern bool -init_sensor_framework(); -extern void -exit_sensor_framework(); -extern int -aee_host_msg_callback(void *msg, uint32_t msg_len); - -int uart_char_cnt = 0; - -static void -uart_irq_callback(const struct device *dev, void *user_data) -{ - unsigned char ch; - - while (uart_poll_in(dev, &ch) == 0) { - uart_char_cnt++; - aee_host_msg_callback(&ch, 1); - } - (void)user_data; -} - -const struct device *uart_dev = NULL; - -static bool -host_init() -{ - uart_dev = device_get_binding(HOST_DEVICE_COMM_UART_NAME); - if (!uart_dev) { - printf("UART: Device driver not found.\n"); - return false; - } - uart_irq_rx_enable(uart_dev); - uart_irq_callback_set(uart_dev, uart_irq_callback); - return true; -} - -int -host_send(void *ctx, const char *buf, int size) -{ - if (!uart_dev) - return 0; - - for (int i = 0; i < size; i++) - uart_poll_out(uart_dev, buf[i]); - - return size; -} - -void -host_destroy() -{} - -/* clang-format off */ -host_interface interface = { - .init = host_init, - .send = host_send, - .destroy = host_destroy -}; -/* clang-format on */ - -timer_ctx_t timer_ctx; - -static char global_heap_buf[350 * 1024] = { 0 }; - -static NativeSymbol native_symbols[] = { - EXPORT_WASM_API_WITH_SIG(display_input_read, "(*)i"), - EXPORT_WASM_API_WITH_SIG(display_flush, "(iiii*)"), - EXPORT_WASM_API_WITH_SIG(display_fill, "(iiii*)"), - EXPORT_WASM_API_WITH_SIG(display_vdb_write, "(*iii*i)"), - EXPORT_WASM_API_WITH_SIG(display_map, "(iiii*)"), - EXPORT_WASM_API_WITH_SIG(time_get_ms, "()i") -}; - -int -iwasm_main() -{ - RuntimeInitArgs init_args; - - host_init(); - - memset(&init_args, 0, sizeof(RuntimeInitArgs)); - - init_args.mem_alloc_type = Alloc_With_Pool; - init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; - init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); - - init_args.native_module_name = "env"; - init_args.n_native_symbols = sizeof(native_symbols) / sizeof(NativeSymbol); - init_args.native_symbols = native_symbols; - - /* initialize runtime environment */ - if (!wasm_runtime_full_init(&init_args)) { - printf("Init runtime environment failed.\n"); - return -1; - } - - display_init(); - - /* timer manager */ - if (!init_wasm_timer()) { - goto fail; - } - - app_manager_startup(&interface); - -fail: - wasm_runtime_destroy(); - return -1; -} diff --git a/samples/multi-thread/wasm-apps/CMakeLists.txt b/samples/multi-thread/wasm-apps/CMakeLists.txt index d7352e427..5442398f9 100644 --- a/samples/multi-thread/wasm-apps/CMakeLists.txt +++ b/samples/multi-thread/wasm-apps/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.14) project(wasm-apps) set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) @@ -43,4 +43,4 @@ add_executable(main_thread_exception.wasm main_thread_exception.c) target_link_libraries(main_thread_exception.wasm) add_executable(main_global_atomic.wasm main_global_atomic.c) -target_link_libraries(main_global_atomic.wasm) \ No newline at end of file +target_link_libraries(main_global_atomic.wasm) diff --git a/samples/shared-heap/CMakeLists.txt b/samples/shared-heap/CMakeLists.txt new file mode 100644 index 000000000..6346d077e --- /dev/null +++ b/samples/shared-heap/CMakeLists.txt @@ -0,0 +1,127 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +include(CheckPIESupported) + +if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") + project (shared_heap_test) +else() + project (shared_heap_test C ASM) +endif() + +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" + +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Debug) +endif () + +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_FAST_INTERP 1) +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_JIT 0) +set (WAMR_BUILD_LIBC_BUILTIN 1) +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_SHARED_HEAP 1) +set (WAMR_BUILD_GC_HEAP_VERIFY 1) + +if (NOT MSVC) + # linker flags + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + endif () + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () + endif () +endif () + +# build out vmlib +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +if (MSVC) + target_compile_definitions(vmlib PRIVATE WASM_API_EXTERN=) +endif() +target_link_libraries(vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) + +################ application related ################ +include_directories(${CMAKE_CURRENT_LIST_DIR}/src) +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +add_executable (shared_heap_test src/main.c ${UNCOMMON_SHARED_SOURCE}) + +check_pie_supported() +set_target_properties (shared_heap_test PROPERTIES POSITION_INDEPENDENT_CODE ON) + +if (APPLE) + target_link_libraries (shared_heap_test vmlib -lm -ldl -lpthread) +else () + target_link_libraries (shared_heap_test vmlib -lm -ldl -lpthread -lrt) +endif () + +add_subdirectory(wasm-apps) + +if (WAMR_BUILD_AOT EQUAL 1) + set (WAMR_COMPILER_DIR ${CMAKE_CURRENT_LIST_DIR}/../../wamr-compiler/build) + message (CHECK_START "Detecting WAMR_COMPILER at ${WAMR_COMPILER_DIR}") + find_file (WAMR_COMPILER + wamrc + PATHS "${CMAKE_CURRENT_LIST_DIR}/../../wamr-compiler/build" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + if (WAMR_COMPILER) + message (CHECK_PASS "found") + else() + message (CHECK_FAIL "not found") + endif() + if (NOT EXISTS ${WAMR_COMPILER}) + message (FATAL_ERROR "Please build wamrc under ${WAMR_ROOT_DIR}/wamr-compiler") + else() + message (STATUS "WAMR_COMPILER is ${WAMR_COMPILER}") + endif() + + add_custom_target( + wasm_to_aot + ALL + DEPENDS wasm-apps/test1.wasm wasm-apps/test2.wasm ${WAMR_COMPILER} + COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test1.aot wasm-apps/test1.wasm + COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test2.aot wasm-apps/test2.wasm + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) +endif() diff --git a/samples/shared-heap/src/main.c b/samples/shared-heap/src/main.c new file mode 100644 index 000000000..f4024f08c --- /dev/null +++ b/samples/shared-heap/src/main.c @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_export.h" +#include "bh_platform.h" +#include "bh_read_file.h" + +typedef struct thread_arg { + bh_queue *queue; + wasm_module_inst_t module_inst; +} thread_arg; + +static void * +thread1_callback(void *arg) +{ + thread_arg *targ = arg; + wasm_module_inst_t module_inst = targ->module_inst; + bh_queue *queue = targ->queue; + wasm_exec_env_t exec_env; + wasm_function_inst_t my_shared_heap_malloc_func; + wasm_function_inst_t my_shared_heap_free_func; + uint32 i, argv[2]; + + /* lookup wasm functions */ + if (!(my_shared_heap_malloc_func = wasm_runtime_lookup_function( + module_inst, "my_shared_heap_malloc")) + || !(my_shared_heap_free_func = wasm_runtime_lookup_function( + module_inst, "my_shared_heap_free"))) { + printf("Failed to lookup function.\n"); + } + + /* create exec env */ + if (!(exec_env = wasm_runtime_create_exec_env(module_inst, 32768))) { + printf("Failed to create exec env.\n"); + return NULL; + } + + /* allocate memory with wasm_runtime_shared_heap_malloc and send it + to wasm app2 */ + for (i = 0; i < 5; i++) { + uint8 *buf; + uint64 offset; + + offset = wasm_runtime_shared_heap_malloc(module_inst, 1024 * (i + 1), + (void **)&buf); + + if (offset == 0) { + printf("Failed to allocate memory from shared heap\n"); + break; + } + + snprintf(buf, 1024, "Hello, this is buf %u allocated from shared heap", + i + 1); + + printf("wasm app1 send buf: %s\n\n", buf); + if (!bh_post_msg(queue, 1, buf, 1024 * i)) { + printf("Failed to post message to queue\n"); + wasm_runtime_shared_heap_free(module_inst, offset); + break; + } + } + + /* allocate memory by calling my_shared_heap_malloc function and send it + to wasm app2 */ + for (i = 5; i < 10; i++) { + uint8 *buf; + + argv[0] = 1024 * (i + 1); + argv[1] = i + 1; + wasm_runtime_call_wasm(exec_env, my_shared_heap_malloc_func, 2, argv); + + if (wasm_runtime_get_exception(module_inst)) { + printf("Failed to call 'my_shared_heap_malloc' function: %s\n", + wasm_runtime_get_exception(module_inst)); + break; + } + if (argv[0] == 0) { + printf("Failed to allocate memory from shared heap\n"); + break; + } + + buf = wasm_runtime_addr_app_to_native(module_inst, argv[0]); + + printf("wasm app1 send buf: %s\n\n", buf); + if (!bh_post_msg(queue, 1, buf, 1024 * i)) { + printf("Failed to post message to queue\n"); + wasm_runtime_shared_heap_free(module_inst, argv[0]); + break; + } + } + + wasm_runtime_destroy_exec_env(exec_env); + + return NULL; +} + +static void +queue_callback(void *message, void *arg) +{ + bh_message_t msg = (bh_message_t)message; + wasm_exec_env_t exec_env = arg; + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + wasm_function_inst_t print_buf_func; + uint32 argv[2]; + + /* lookup wasm function */ + if (!(print_buf_func = + wasm_runtime_lookup_function(module_inst, "print_buf"))) { + printf("Failed to lookup function.\n"); + return; + } + + char *buf = bh_message_payload(msg); + printf("wasm app's native queue received buf: %s\n\n", buf); + + /* call wasm function */ + argv[0] = wasm_runtime_addr_native_to_app(module_inst, buf); + wasm_runtime_call_wasm(exec_env, print_buf_func, 1, argv); + if (wasm_runtime_get_exception(module_inst)) { + printf("Failed to call 'print_buf' function: %s\n", + wasm_runtime_get_exception(module_inst)); + } +} + +static void * +thread2_callback(void *arg) +{ + thread_arg *targ = arg; + bh_queue *queue = targ->queue; + wasm_module_inst_t module_inst = targ->module_inst; + wasm_exec_env_t exec_env; + + /* create exec env */ + if (!(exec_env = wasm_runtime_create_exec_env(module_inst, 32768))) { + printf("Failed to create exec env.\n"); + return NULL; + } + + /* enter queue's message loop until bh_queue_exit_loop_run + is called */ + bh_queue_enter_loop_run(queue, queue_callback, exec_env); + + wasm_runtime_destroy_exec_env(exec_env); + + return NULL; +} + +static char global_heap_buf[512 * 1024]; + +int +main(int argc, char **argv) +{ + char *wasm_file1 = NULL, *wasm_file2 = NULL; + uint8 *wasm_file1_buf = NULL, *wasm_file2_buf = NULL; + uint32 wasm_file1_size, wasm_file2_size; + wasm_module_t wasm_module1 = NULL, wasm_module2 = NULL; + wasm_module_inst_t module_inst1 = NULL; + wasm_module_inst_t module_inst2 = NULL; + wasm_shared_heap_t shared_heap = NULL; + bh_queue *queue = NULL; + RuntimeInitArgs init_args; + SharedHeapInitArgs heap_init_args; + char error_buf[128] = { 0 }; + bool aot_mode = false; + int ret = -1; + + if (argc > 1 && !strcmp(argv[1], "--aot")) + aot_mode = true; + + if (!aot_mode) + printf("Test shared heap in interpreter mode\n\n"); + else + printf("Test shared heap in AOT mode\n\n"); + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + /* init wasm runtime */ + if (!wasm_runtime_full_init(&init_args)) { + printf("Init runtime environment failed.\n"); + return -1; + } + + /* create queue */ + if (!(queue = bh_queue_create())) { + printf("Create queue failed.\n"); + goto fail; + } + + /* read wasm file */ + if (!aot_mode) + wasm_file1 = "./wasm-apps/test1.wasm"; + else + wasm_file1 = "./wasm-apps/test1.aot"; + if (!(wasm_file1_buf = + bh_read_file_to_buffer(wasm_file1, &wasm_file1_size))) { + printf("Open wasm file %s failed.\n", wasm_file1); + goto fail; + } + + /* load wasm file */ + wasm_module1 = wasm_runtime_load((uint8 *)wasm_file1_buf, wasm_file1_size, + error_buf, sizeof(error_buf)); + if (!wasm_module1) { + printf("Load wasm module failed. error: %s\n", error_buf); + goto fail; + } + + /* instantiate module */ + module_inst1 = wasm_runtime_instantiate(wasm_module1, 65536, 0, error_buf, + sizeof(error_buf)); + if (!module_inst1) { + printf("Instantiate wasm module failed. error: %s\n", error_buf); + goto fail; + } + + /* read wasm file */ + if (!aot_mode) + wasm_file2 = "./wasm-apps/test2.wasm"; + else + wasm_file2 = "./wasm-apps/test2.aot"; + if (!(wasm_file2_buf = + bh_read_file_to_buffer(wasm_file2, &wasm_file2_size))) { + printf("Open wasm file %s failed.\n", wasm_file1); + goto fail; + } + + /* load wasm file */ + wasm_module2 = wasm_runtime_load((uint8 *)wasm_file2_buf, wasm_file2_size, + error_buf, sizeof(error_buf)); + if (!wasm_module2) { + printf("Load wasm module failed. error: %s\n", error_buf); + goto fail; + } + + /* instantiate module */ + module_inst2 = wasm_runtime_instantiate(wasm_module2, 65536, 0, error_buf, + sizeof(error_buf)); + if (!module_inst2) { + printf("Instantiate wasm module failed. error: %s\n", error_buf); + goto fail; + } + + /* create shared heap */ + memset(&heap_init_args, 0, sizeof(heap_init_args)); + heap_init_args.size = 65536; + shared_heap = wasm_runtime_create_shared_heap(&heap_init_args); + if (!shared_heap) { + printf("Create shared heap failed. error: %s\n", error_buf); + goto fail; + } + + /* attach module instance 1 to the shared heap */ + if (!wasm_runtime_attach_shared_heap(module_inst1, shared_heap)) { + printf("Attach shared heap failed.\n"); + goto fail; + } + + /* attach module instance 2 to the shared heap */ + if (!wasm_runtime_attach_shared_heap(module_inst2, shared_heap)) { + printf("Attach shared heap failed.\n"); + goto fail; + } + + /* create thread 1 */ + struct thread_arg targ1 = { 0 }; + korp_tid tid1; + targ1.queue = queue; + targ1.module_inst = module_inst1; + if (os_thread_create(&tid1, thread1_callback, &targ1, + APP_THREAD_STACK_SIZE_DEFAULT)) { + printf("Failed to create thread 1\n"); + goto fail; + } + + /* create thread 2 */ + struct thread_arg targ2 = { 0 }; + korp_tid tid2; + targ2.queue = queue; + targ2.module_inst = module_inst2; + if (os_thread_create(&tid2, thread2_callback, &targ2, + APP_THREAD_STACK_SIZE_DEFAULT)) { + printf("Failed to create thread 2\n"); + os_thread_join(tid1, NULL); + goto fail; + } + + /* wait until all messages are post to wasm app2 and wasm app2 + handles all of them, then exit the queue message loop */ + usleep(10000); + bh_queue_exit_loop_run(queue); + + os_thread_join(tid1, NULL); + os_thread_join(tid2, NULL); + + ret = 0; + +fail: + if (module_inst2) + wasm_runtime_deinstantiate(module_inst2); + + if (module_inst1) + wasm_runtime_deinstantiate(module_inst1); + + if (wasm_module2) + wasm_runtime_unload(wasm_module2); + + if (wasm_module1) + wasm_runtime_unload(wasm_module1); + + if (wasm_file2_buf) + wasm_runtime_free(wasm_file2_buf); + + if (wasm_file1_buf) + wasm_runtime_free(wasm_file1_buf); + + if (queue) + bh_queue_destroy(queue); + + wasm_runtime_destroy(); + + return ret; +} diff --git a/samples/shared-heap/wasm-apps/CMakeLists.txt b/samples/shared-heap/wasm-apps/CMakeLists.txt new file mode 100644 index 000000000..c0010af6a --- /dev/null +++ b/samples/shared-heap/wasm-apps/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) +project(wasm-apps) + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +if (APPLE) + set (HAVE_FLAG_SEARCH_PATHS_FIRST 0) + set (CMAKE_C_LINK_FLAGS "") + set (CMAKE_CXX_LINK_FLAGS "") +endif () + +set (CMAKE_SYSTEM_PROCESSOR wasm32) +set (CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot) + +if (NOT DEFINED WASI_SDK_DIR) + set (WASI_SDK_DIR "/opt/wasi-sdk") +endif () + +set (CMAKE_C_FLAGS "-nostdlib -Qunused-arguments -z stack-size=32768") +set (CMAKE_C_COMPILER_TARGET "wasm32") +set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") + +set (DEFINED_SYMBOLS "${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt") + +set (CMAKE_EXE_LINKER_FLAGS + "-O0 -Wl,--initial-memory=65536, \ + -Wl,--no-entry,--strip-all, \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--export=__wasm_call_ctors \ + -Wl,--export=my_shared_heap_malloc \ + -Wl,--export=my_shared_heap_free \ + -Wl,--export=print_buf \ + -Wl,--allow-undefined" +) + +add_executable(test1.wasm test1.c) +target_link_libraries(test1.wasm) + +add_executable(test2.wasm test2.c) +target_link_libraries(test2.wasm) diff --git a/samples/shared-heap/wasm-apps/test1.c b/samples/shared-heap/wasm-apps/test1.c new file mode 100644 index 000000000..c8fe0c755 --- /dev/null +++ b/samples/shared-heap/wasm-apps/test1.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include + +extern void * +shared_heap_malloc(uint32_t size); +extern void +shared_heap_free(void *ptr); + +void * +my_shared_heap_malloc(uint32_t size, uint32_t index) +{ + char *buf1 = NULL, *buf2 = NULL, *buf; + + buf1 = shared_heap_malloc(128); + if (!buf1) + return NULL; + + buf1[0] = 'H'; + buf1[1] = 'e'; + buf1[2] = 'l'; + buf1[3] = 'l'; + buf1[4] = 'o'; + buf1[5] = ','; + buf1[6] = ' '; + + buf2 = shared_heap_malloc(128); + if (!buf2) { + shared_heap_free(buf1); + return NULL; + } + + snprintf(buf2, 128, "this is buf %u allocated from shared heap", index); + + buf = shared_heap_malloc(size); + if (!buf) { + shared_heap_free(buf1); + shared_heap_free(buf2); + return NULL; + } + + memset(buf, 0, size); + memcpy(buf, buf1, strlen(buf1)); + memcpy(buf + strlen(buf1), buf2, strlen(buf2)); + + shared_heap_free(buf1); + shared_heap_free(buf2); + return buf; +} + +void +my_shared_heap_free(void *ptr) +{ + shared_heap_free(ptr); +} diff --git a/samples/shared-heap/wasm-apps/test2.c b/samples/shared-heap/wasm-apps/test2.c new file mode 100644 index 000000000..b63efcd1a --- /dev/null +++ b/samples/shared-heap/wasm-apps/test2.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +#include + +extern void +shared_heap_free(void *ptr); + +void +print_buf(char *buf) +{ + printf("wasm app2's wasm func received buf: %s\n\n", buf); + shared_heap_free(buf); +} diff --git a/samples/spawn-thread/wasm-apps/CMakeLists.txt b/samples/spawn-thread/wasm-apps/CMakeLists.txt index 0996d5841..df21b4485 100644 --- a/samples/spawn-thread/wasm-apps/CMakeLists.txt +++ b/samples/spawn-thread/wasm-apps/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.14) project(wasm-apps) set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) diff --git a/test-tools/dynamic-aot-debug/README.md b/test-tools/dynamic-aot-debug/README.md new file mode 100644 index 000000000..6325a803a --- /dev/null +++ b/test-tools/dynamic-aot-debug/README.md @@ -0,0 +1,139 @@ +# Dynamic AOT Module Debugging + +> Note: Dynamic AOT debugging is experimental and only a few debugging capabilities are supported. + +This guide explains how to debug WAMR AOT modules with dynamic AOT features. Follow these steps to set up and run your debugging environment. + +## 1. Test source code + +The following c program file is used as a debugging test file. + +```bash +#include + +int main() { + printf("hello, world!\n"); + int a = 1024; + printf("a is %d\n",a); + int b = 42; + printf("b is %d\n",b); + return 0; +} +``` + +## 2. Build iwasm with dynamic aot debugging feature + +To enable dynamic AOT debugging, ensure the following +compile options are enabled when you [build iwasm](../../product-mini/README.md): + +```bash +cmake -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_DYNAMIC_AOT_DEBUG=1 -DCMAKE_BUILD_TYPE=Debug +``` + +## 3. Build wamrc + +Developer may need to build out two versions of wamrc, one is to compile the wasm binary into the AOT file, the other is to compile the wasm binary into an object file. To build out the former, just build wamrc as normal, see [wamrc-compiler/README.md](../../wamr-compiler/README.md). To build out the latter, the `WAMR_BUILD_DEBUG_AOT` flag must be added to cmake, please refer to the first two steps in [doc/source_debugging_aot.md](../../doc/source_debugging_aot.md), and if you encounter the error “‘eLanguageTypeC17’ not declared in this scope”, you can bypass it by commenting out the case judgments. This will not affect the debugging results. + +## 4. Dynamic aot debugging and verification across various platforms + +You can adjust the compiler options for different architectures and instruction sets. + +### 4.1 Linux + +#### Compile test.c to test.wasm + +```bash +/opt/wasi-sdk/bin/clang -O0 -g -gdwarf-2 -o test.wasm test.c +``` + +#### Compile test.wasm to test.aot + +```bash +./wamrc --opt-level=0 -o test.aot test.wasm +``` + +#### Compile test.wasm to test object file + +> Note: please use the version wamrc which was built with `cmake -DWAMR_BUILD_DEBUG_AOT` flag. + +```bash +./wamrc --opt-level=0 --format=object -o test.obj test.wasm +``` + +#### Launch the program using gdbserver on the remote linux host + +```bash +cd ~/aot_debug # This directory contains iwasm and test.aot +gdbserver hostip:port ./iwasm test.aot +``` + +#### Local remote debugging + +```bash +expport OBJ_PATH=~/aot_debug +cd ~/aot_debug # This directory contains iwasm, test.c, test obj file and dynamic_aot_debug.py +gdb ./iwasm +(gdb) target remote hostip:port +(gdb) source dynamic_aot_debug.py +(gdb) c +(gdb) b test.c:main +(gdb) n +``` + +### 4.2 ARMv7 + +#### Compile test.c to test.wasm + +```bash +/opt/wasi-sdk/bin/clang -O0 -nostdlib -z stack-size=8192 -Wl,--initial-memory=65536 +-g -gdwarf-2 -o test.wasm test.c -Wl,--export=main -Wl,--export=__main_argc_argv +-Wl,--export=__heap_base -Wl,--export=__data_end -Wl,--no-entry -Wl,--allow-undefined +``` + +#### Compile test.wasm to test.aot + +```bash +./wamrc --opt-level=0 --target=thumbv7 --target-abi=gnueabihf --cpu=cortex-a7 +--cpu-features=-neon -o test.aot test.wasm +``` + +#### Compile test.wasm to test object file + +> Note: please use the version wamrc which was built with `cmake -DWAMR_BUILD_DEBUG_AOT` flag. + +```bash +./wamrc --opt-level=0 --format=object --target=thumbv7 --target-abi=gnueabihf +--cpu=cortex-a7 --cpu-features=-neon -o test.obj test.wasm +``` + +#### Start Emulator + +In Terminal 1, start the emulator in debug mode and launch the GDB server: + +```bash +# start emulator on debug mode, and will start gdb server, set port as 1234 +./emulator.sh vela -qemu -S -s +ap> iwasm test.aot +``` + +#### Start NuttX Using GDB + +In Terminal 2, set the path to your object file and start NuttX with GDB: + +```bash +# You can save test.obj file in this path +export OBJ_PATH=~/work/data/aot_debug +gdb-multiarch nuttx -ex "tar remote:1234" -ex "source dynamic_aot_debug.py" +``` + +In the GDB prompt: + +```bash +(gdb) c +(gdb) b test.c:main +(gdb) n +``` + +## 5. Workflow + +Refer to the workflow diagram (wasm-micro-runtime/test-tools/dynamic-aot-debug) for an overview of the debugging process. In addition, the implementation of this dynamic aot debugging solution is not complete yet. It only supports breakpoints and single-step execution, and it is not yet known to view detailed information such as variables. diff --git a/test-tools/dynamic-aot-debug/dynamic_aot_debug.py b/test-tools/dynamic-aot-debug/dynamic_aot_debug.py new file mode 100644 index 000000000..1548954f4 --- /dev/null +++ b/test-tools/dynamic-aot-debug/dynamic_aot_debug.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 XiaoMi Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +import os +import gdb + +# Get object file path from environment variable or use default value +path_objs = os.getenv("OBJ_PATH", "~/objects/") + +# Expand user directory symbol (~) +path_objs = os.path.expanduser(path_objs) +print(f"Object files will be loaded from: {path_objs} on localhost") + + +def add_symbol_with_aot_info(aot_module_info): + """Add symbol file with AOT information to GDB and list current breakpoints.""" + try: + text_addr = aot_module_info.get("code") + file_name = aot_module_info.get("name") + + if not text_addr or not file_name: + print("Error: 'code' or 'name' missing in AOT module info.") + return + + # Extract base file name without extension + file_name_without_extension, _ = os.path.splitext(file_name) + + # Remove directory part if present + file_name = os.path.basename(file_name_without_extension) + + # Add .obj extension to the file name + file_name = file_name + ".obj" + + # Construct the path for the symbol file + path_symfile = os.path.join(path_objs, file_name) + + # Construct the command to add the symbol file + cmd = f"add-symbol-file {path_symfile} {text_addr}" + gdb.execute(cmd) + + # Print current breakpoints + breakpoints = gdb.execute("info breakpoints", to_string=True) + print("Current breakpoints:", breakpoints) + + except gdb.error as e: + print(f"GDB error: {e}") + except Exception as e: + print(f"Unexpected error: {e}") + + +class ReadGDynamicAotModule(gdb.Command): + """Command to read the g_dynamic_aot_module structure and extract information.""" + + def __init__(self): + super(self.__class__, self).__init__("read_gda", gdb.COMMAND_USER) + + def invoke(self, args, from_tty): + """Retrieve and process the g_dynamic_aot_module structure.""" + try: + aot_module = gdb.parse_and_eval("g_dynamic_aot_module") + aot_module_info = {} + + # Ensure aot_module is a pointer and dereference it + if aot_module.type.code == gdb.TYPE_CODE_PTR: + aot_module = aot_module.dereference() + + # Check if it's a structure type + if aot_module.type.strip_typedefs().code == gdb.TYPE_CODE_STRUCT: + for field in aot_module.type.fields(): + field_name = field.name + var = aot_module[field_name] + + if field_name == "name": + aot_module_info["name"] = var.string() + elif field_name == "code": + aot_module_info["code"] = str(var) + + if "name" in aot_module_info and "code" in aot_module_info: + add_symbol_with_aot_info(aot_module_info) + else: + print("Could not find 'name' or 'code' in Aot_module.") + else: + print("Aot_module is not of struct type.") + else: + print("Aot_module is not a pointer type.") + except gdb.error as e: + print(f"An error occurred: {e}") + + +def init(): + """Initialize environment and set up debugger.""" + # Register the command to gdb + ReadGDynamicAotModule() + + # Set a breakpoint at function __enable_dynamic_aot_debug + breakpoint = gdb.Breakpoint("__enable_dynamic_aot_debug") + # Attach the self-defined command to the created breakpoint, read_gda means read global dynamic aot info. + breakpoint.commands = "read_gda" + + +init() diff --git a/test-tools/dynamic-aot-debug/dynamic_aot_debug_workflow.svg b/test-tools/dynamic-aot-debug/dynamic_aot_debug_workflow.svg new file mode 100644 index 000000000..fc81cb87a --- /dev/null +++ b/test-tools/dynamic-aot-debug/dynamic_aot_debug_workflow.svg @@ -0,0 +1,17 @@ + + + + + + + + load python scriptPCrun python initset breakpoint $1 on __enable_dynamic_aot_debugRegister "read_gda" command into gdbBind readl_gda to breakpoint $1trigger breakpointexcute "read_gda" commandnoyesRead and parse code_addr and module name from g_dynamic_aot_moduleGet the file name, text segment address of the dynamically aot loaded moduleExecute add-symbol-file test -s text 0x408f10f8 to load the debugging information fileiwasm test.aotset breakpoint $2, b test.aot main contiuewasm_runtime_set_module_name__enable_dynamic_aot_debug_ptrtrigger breakpoint $1gdb continue ?run nuttxGDB run nuttx andconnect to gdb servertrigger breakpoint $2debug test.aot programnowaityes12nuttxexitcall load_aot_module_destroytest/obj filetest.wasmwamrccall aot_unloadWASM_ENABLE_DYNAMIC_AOT_DEBUG=1test.cwasi-SDKWAMR_BUILD_DEBUG_AOT=1aot_set_module_name \ No newline at end of file diff --git a/test-tools/ip2function/ip2function.py b/test-tools/ip2function/ip2function.py new file mode 100644 index 000000000..fb8ecd17d --- /dev/null +++ b/test-tools/ip2function/ip2function.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 Amazon Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +""" +This tool corrects function names in call stacks based on the +instruction pointers. + +When the AOT file is generated with excluded func-idx in the +`--call-stack-features` parameter, the function indexes are +incorrect (likely they're zero). This script uses instruction +pointers and the original WASM file to generate a call stack +file with the correct function indexes (or function names, +when available). + +Example input (call_stack.txt) - note that `__imported_wasi_snapshot_preview1_fd_close` +had index 0, therefore it appears as a name in every line: +``` +#00: 0x0505 - __imported_wasi_snapshot_preview1_fd_close +#01: 0x0309 - __imported_wasi_snapshot_preview1_fd_close +#02: 0x037c - __imported_wasi_snapshot_preview1_fd_close +#03: 0x03b2 - __imported_wasi_snapshot_preview1_fd_close +#04: 0x03e4 - __imported_wasi_snapshot_preview1_fd_close +#05: 0x02e6 - __imported_wasi_snapshot_preview1_fd_close +``` + +Conversion command: +``` +python3 test-tools/ip2function/ip2function.py \ + --wasm-file opt-samp/tiny.wasm \ + call_stack.txt +``` + +Output: +``` +#0: 0x0505 - abort +#1: 0x0309 - baz +#2: 0x037c - bar +#3: 0x03b2 - foo +#4: 0x03e4 - __original_main +#5: 0x02e6 - _start +``` +""" + +import argparse +import bisect +import os +import re +import subprocess +import sys + +from typing import NamedTuple, Optional +from typing import TextIO +from pathlib import Path +import shutil + + +class FunctionInfo(NamedTuple): + start_address: int + idx: int + name: Optional[str] + + def __str__(self) -> str: + return self.name if self.name else f"$f{self.idx}" + + +def load_functions(wasm_objdump: Path, wasm_file: Path) -> list[FunctionInfo]: + objdump_function_pattern = re.compile( + r"^([0-9a-f]+)\sfunc\[(\d+)\](?:\s\<(.+)\>)?\:$" + ) + + def parse_objdump_function_line( + line: str, + ) -> Optional[FunctionInfo]: + match = objdump_function_pattern.match(line.strip()) + return ( + FunctionInfo(int(match[1], 16), int(match[2]), match[3]) if match else None + ) + + p = subprocess.run( + [wasm_objdump, "--disassemble", wasm_file], + check=True, + capture_output=True, + text=True, + universal_newlines=True, + ) + + return list( + filter( + None, + ( + parse_objdump_function_line(line.strip()) + for line in p.stdout.split(os.linesep) + ), + ) + ) + + +def parse_call_stack_file( + functions: list[FunctionInfo], call_stack_file: TextIO, output_file: TextIO +) -> None: + call_stack_line_pattern = re.compile(r"^(#\d+): (0x[0-9a-f]+) \- (\S+)$") + for line in call_stack_file: + match = call_stack_line_pattern.match(line.strip()) + if not match: + output_file.write(line) + continue + index = match[1] + address = match[2] + + func_pos = bisect.bisect_right( + functions, int(address, 16), key=lambda x: x.start_address + ) + if func_pos <= 0: + raise ValueError(f"Cannot find function for address {address}") + output_file.write(f"{index}: {address} - {functions[func_pos -1]}\n") + + +def main() -> int: + parser = argparse.ArgumentParser(description="addr2line for wasm") + parser.add_argument( + "--wasm-objdump", type=Path, default="wasm-objdump", help="path to wasm objdump" + ) + parser.add_argument( + "--wasm-file", required=True, type=Path, help="path to wasm file" + ) + parser.add_argument( + "call_stack_file", type=argparse.FileType("r"), help="path to a call stack file" + ) + parser.add_argument( + "-o", + "--output", + type=argparse.FileType("w"), + default=sys.stdout, + help="Output file path (default is stdout)", + ) + + args = parser.parse_args() + + wasm_objdump: Path = shutil.which(args.wasm_objdump) + assert wasm_objdump is not None + + wasm_file: Path = args.wasm_file + assert wasm_file.exists() + + parse_call_stack_file( + load_functions(wasm_objdump, wasm_file), args.call_stack_file, args.output + ) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/fuzz/wasm-mutator-fuzz/portal/osv-scanner.toml b/tests/fuzz/wasm-mutator-fuzz/portal/osv-scanner.toml new file mode 100644 index 000000000..1eb55cd8d --- /dev/null +++ b/tests/fuzz/wasm-mutator-fuzz/portal/osv-scanner.toml @@ -0,0 +1,52 @@ +# GHSA-67hx-6x53-jw92 +[[PackageOverrides]] +name = "@babel/traverse" +ecosystem = "npm" +ignore = true +reason = "Accepted known vulnerabilities for testing purposes" + +# GHSA-67hx-6x53-jw92 +[[PackageOverrides]] +name = "babel-traverse" +ecosystem = "npm" +ignore = true +reason = "Accepted known vulnerabilities for testing purposes" + +# GHSA-9c47-m6qq-7p4h +[[PackageOverrides]] +name = "json5" +ecosystem = "npm" +ignore = true +reason = "Dependency not critical for security" + +# GHSA-7fh5-64p2-3v2j +[[PackageOverrides]] +name = "postcss" +ecosystem = "npm" +ignore = true +reason = "Vulnerabilities do not affect current use case" + +# GHSA-gcx4-mw62-g8wm +[[PackageOverrides]] +name = "rollup" +ecosystem = "npm" +ignore = true +reason = "Legacy build tool under controlled environment" + +# GHSA-c2qf-rxjj-qqgw +[[PackageOverrides]] +name = "semver" +ecosystem = "npm" +ignore = true +reason = "Version parsing is managed securely" + +# GHSA-353f-5xf4-qw67 +# GHSA-c24v-8rfc-w8vw +# GHSA-8jhw-289h-jh2g +# GHSA-64vr-g452-qvp3 +# GHSA-9cwx-2883-4wfx +[[PackageOverrides]] +name = "vite" +ecosystem = "npm" +ignore = true +reason = "Development server not exposed to untrusted networks" diff --git a/tests/fuzz/wasm-mutator-fuzz/server/osv-scanner.toml b/tests/fuzz/wasm-mutator-fuzz/server/osv-scanner.toml new file mode 100644 index 000000000..430d8ca8c --- /dev/null +++ b/tests/fuzz/wasm-mutator-fuzz/server/osv-scanner.toml @@ -0,0 +1,32 @@ +# GHSA-m2qf-hxjv-5gpq / PYSEC-2023-62 +[[PackageOverrides]] +name = "Flask" +ecosystem = "PyPI" +ignore = true +reason = "Accepted known vulnerabilities for testing purposes" + +# GHSA-m2qf-hxjv-5gpq / PYSEC-2023-62 +[[PackageOverrides]] +name = "flask" +ecosystem = "PyPI" +ignore = true +reason = "Accepted known vulnerabilities for testing purposes" + +# GHSA-84pr-m4jr-85g5 +# GHSA-hxwh-jpp2-84pm / PYSEC-2024-71 +[[PackageOverrides]] +name = "flask-cors" +ecosystem = "PyPI" +ignore = true +reason = "Accepted known vulnerabilities for testing purposes" + +# GHSA-2g68-c3qc-8985 +# GHSA-hrfv-mqp8-q5rw / PYSEC-2023-221 +# GHSA-px8h-6qxv-m22q / PYSEC-2023-57 +# GHSA-xg9f-g7g7-2323 / PYSEC-2023-58 +# PYSEC-2022-203 +[[PackageOverrides]] +name = "werkzeug" +ecosystem = "PyPI" +ignore = true +reason = "Accepted known vulnerabilities for testing purposes" diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 40c9bb6ae..9f7a69229 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -50,3 +50,4 @@ add_subdirectory(linux-perf) add_subdirectory(gc) add_subdirectory(memory64) add_subdirectory(tid-allocator) +add_subdirectory(shared-heap) \ No newline at end of file diff --git a/tests/unit/runtime-common/wasm-apps/main.aot b/tests/unit/runtime-common/wasm-apps/main.aot deleted file mode 100644 index 79319145a..000000000 Binary files a/tests/unit/runtime-common/wasm-apps/main.aot and /dev/null differ diff --git a/tests/unit/shared-heap/CMakeLists.txt b/tests/unit/shared-heap/CMakeLists.txt new file mode 100644 index 000000000..6baf420f8 --- /dev/null +++ b/tests/unit/shared-heap/CMakeLists.txt @@ -0,0 +1,59 @@ +# Copyright (C) 2024 Xiaomi Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) + +project(test-shared-heap) + +add_definitions(-DRUN_ON_LINUX) + +set(WAMR_BUILD_APP_FRAMEWORK 0) +set(WAMR_BUILD_AOT 0) +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_MEMORY64 1) +set(WAMR_BUILD_SHARED_HEAP 1) + +# Compile wasm modules +add_subdirectory(wasm-apps) + +# if only load this CMake other than load it as subdirectory +include(../unit_common.cmake) + +set(LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") + +if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message(FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +endif () + +set(CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include(${IWASM_DIR}/compilation/iwasm_compl.cmake) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +file(GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set(UNIT_SOURCE ${source_all}) + +aux_source_directory(. SRC_LIST) + +set(unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ${UNCOMMON_SHARED_SOURCE} + ${SRC_LIST} + ) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable(shared_heap_test ${unit_test_sources}) + +target_link_libraries(shared_heap_test ${LLVM_AVAILABLE_LIBS} gtest_main) + +gtest_discover_tests(shared_heap_test) \ No newline at end of file diff --git a/tests/unit/shared-heap/shared_heap_test.cc b/tests/unit/shared-heap/shared_heap_test.cc new file mode 100644 index 000000000..5e45d3111 --- /dev/null +++ b/tests/unit/shared-heap/shared_heap_test.cc @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2024 Xiaomi Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "wasm_runtime_common.h" + +class shared_heap_test : public testing::Test +{ + protected: + virtual void SetUp() {} + static void SetUpTestCase() {} + virtual void TearDown() {} + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +struct ret_env { + wasm_exec_env_t exec_env; + wasm_module_t wasm_module; + wasm_module_inst_t wasm_module_inst; + unsigned char *wasm_file_buf; + char error_buf[128]; +}; + +struct ret_env +load_wasm(char *wasm_file_tested, unsigned int app_heap_size) +{ + std::string wasm_mem_page = wasm_file_tested; + const char *wasm_file = strdup(wasm_mem_page.c_str()); + wasm_module_inst_t wasm_module_inst = nullptr; + wasm_module_t wasm_module = nullptr; + wasm_exec_env_t exec_env = nullptr; + unsigned char *wasm_file_buf = nullptr; + unsigned int wasm_file_size = 0; + unsigned int stack_size = 16 * 1024, heap_size = app_heap_size; + char error_buf[128] = { 0 }; + struct ret_env ret_module_env; + + memset(ret_module_env.error_buf, 0, 128); + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + if (!wasm_file_buf) { + goto fail; + } + + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + if (!wasm_module) { + memcpy(ret_module_env.error_buf, error_buf, 128); + goto fail; + } + + wasm_module_inst = wasm_runtime_instantiate( + wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf)); + if (!wasm_module_inst) { + memcpy(ret_module_env.error_buf, error_buf, 128); + goto fail; + } + + exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size); + +fail: + ret_module_env.exec_env = exec_env; + ret_module_env.wasm_module = wasm_module; + ret_module_env.wasm_module_inst = wasm_module_inst; + ret_module_env.wasm_file_buf = wasm_file_buf; + + return ret_module_env; +} + +void +destroy_module_env(struct ret_env module_env) +{ + if (module_env.exec_env) { + wasm_runtime_destroy_exec_env(module_env.exec_env); + } + + if (module_env.wasm_module_inst) { + wasm_runtime_deinstantiate(module_env.wasm_module_inst); + } + + if (module_env.wasm_module) { + wasm_runtime_unload(module_env.wasm_module); + } + + if (module_env.wasm_file_buf) { + wasm_runtime_free(module_env.wasm_file_buf); + } +} + +TEST_F(shared_heap_test, test_shared_heap) +{ + struct ret_env tmp_module_env; + WASMFunctionInstanceCommon *func_test = nullptr; + bool ret = false; + uint32 argv[1] = { 65535 }; + const char *exception = nullptr; + SharedHeapInitArgs args; + WASMSharedHeap *shared_heap = nullptr; + + args.size = 1024; + shared_heap = wasm_runtime_create_shared_heap(&args); + tmp_module_env = load_wasm((char *)"test.wasm", 0); + + if (!shared_heap) { + printf("Failed to create shared heap\n"); + goto test_failed; + } + if (!wasm_runtime_attach_shared_heap(tmp_module_env.wasm_module_inst, shared_heap)) { + printf("Failed to attach shared heap\n"); + goto test_failed; + } + func_test = wasm_runtime_lookup_function( + tmp_module_env.wasm_module_inst, "test"); + if (!func_test) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto test_failed; + } + + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_test, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + const char *s = wasm_runtime_get_exception(tmp_module_env.wasm_module_inst); + printf("exception: %s\n", s); + goto test_failed; + } + + wasm_runtime_detach_shared_heap(tmp_module_env.wasm_module_inst); + + EXPECT_EQ(10, argv[0]); + + destroy_module_env(tmp_module_env); + return; +test_failed: + destroy_module_env(tmp_module_env); + EXPECT_EQ(1, 0); +} diff --git a/tests/unit/shared-heap/wasm-apps/CMakeLists.txt b/tests/unit/shared-heap/wasm-apps/CMakeLists.txt new file mode 100644 index 000000000..3627a2c14 --- /dev/null +++ b/tests/unit/shared-heap/wasm-apps/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2024 Xiaomi Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) +project(wasm-apps) + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) + +set(CMAKE_SYSTEM_PROCESSOR wasm32) +set(CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot) + +if (NOT DEFINED WASI_SDK_DIR) + set(WASI_SDK_DIR "/opt/wasi-sdk") +endif () + +set(CMAKE_C_FLAGS "-nostdlib -pthread -Qunused-arguments") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -z stack-size=8192 -nostdlib -O0") +set(CMAKE_C_COMPILER_TARGET "wasm32") +set(CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") + +set(DEFINED_SYMBOLS + "${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt") + +set(CMAKE_EXE_LINKER_FLAGS + "-Wl,--no-entry \ + -Wl,--initial-memory=65536 \ + -Wl,--export-all \ + -Wl,--allow-undefined" + ) + +add_executable(test.wasm test.c) +target_link_libraries(test.wasm) + +add_custom_command(TARGET test.wasm POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_BINARY_DIR}/test.wasm + ${CMAKE_CURRENT_BINARY_DIR}/../ + COMMENT "Copy test.wasm to the same directory of google test" + ) \ No newline at end of file diff --git a/tests/unit/shared-heap/wasm-apps/test.c b/tests/unit/shared-heap/wasm-apps/test.c new file mode 100644 index 000000000..b83ee64ff --- /dev/null +++ b/tests/unit/shared-heap/wasm-apps/test.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 Xiaomi Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +extern void * +shared_heap_malloc(int size); +extern void +shared_heap_free(void *offset); + +int +test() +{ + int *ptr = (int *)shared_heap_malloc(10); + + *ptr = 10; + int a = *ptr; + shared_heap_free(ptr); + return a; +} diff --git a/tests/unit/wasm-vm/wasm-apps/binarydump b/tests/unit/wasm-vm/wasm-apps/binarydump deleted file mode 100755 index e7c4d2a1d..000000000 Binary files a/tests/unit/wasm-vm/wasm-apps/binarydump and /dev/null differ diff --git a/tests/unit/wasm-vm/wasm-apps/build.sh b/tests/unit/wasm-vm/wasm-apps/build.sh index dbf062ae7..28496ff2f 100755 --- a/tests/unit/wasm-vm/wasm-apps/build.sh +++ b/tests/unit/wasm-vm/wasm-apps/build.sh @@ -1,6 +1,17 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +readonly CURR_DIR=$PWD +readonly BINARYDUMP_DIR=$PWD/../../../../test-tools/binarydump-tool + +# build binarydump +cd $BINARYDUMP_DIR +mkdir -p build && cd build +cmake .. && make -j +cp -a binarydump $CURR_DIR + +cd $CURR_DIR + ## build app1 /opt/wasi-sdk/bin/clang -O3 \ -z stack-size=4096 -Wl,--initial-memory=65536 \ diff --git a/tests/wamr-test-suites/spec-test-script/memory64_ignore_cases.patch b/tests/wamr-test-suites/spec-test-script/memory64_ignore_cases.patch index 5e7afd9d1..afd0536d9 100644 --- a/tests/wamr-test-suites/spec-test-script/memory64_ignore_cases.patch +++ b/tests/wamr-test-suites/spec-test-script/memory64_ignore_cases.patch @@ -1,5 +1,5 @@ diff --git a/test/core/address.wast b/test/core/address.wast -index 8e52030..de0d0cb 100644 +index 8e52030e..de0d0cb9 100644 --- a/test/core/address.wast +++ b/test/core/address.wast @@ -210,7 +210,7 @@ @@ -12,7 +12,7 @@ index 8e52030..de0d0cb 100644 "(memory 1)" "(func (drop (i32.load offset=4294967296 (i32.const 0))))" diff --git a/test/core/binary.wast b/test/core/binary.wast -index 4090b2c..18f66b4 100644 +index 4090b2cd..18f66b42 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -206,7 +206,7 @@ @@ -70,7 +70,7 @@ index 4090b2c..18f66b4 100644 ;; Start section (module binary diff --git a/test/core/data.wast b/test/core/data.wast -index 4f339be..0b5b3e6 100644 +index 4f339bed..0b5b3e6b 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -306,9 +306,10 @@ @@ -124,7 +124,7 @@ index 4f339be..0b5b3e6 100644 ;; Invalid offsets diff --git a/test/core/elem.wast b/test/core/elem.wast -index 575ecef..dd1106c 100644 +index 575ecef8..dd1106c7 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -562,6 +562,7 @@ @@ -151,7 +151,7 @@ index 575ecef..dd1106c 100644 (assert_return (invoke $module1 "call-9") (i32.const 70)) +;) diff --git a/test/core/global.wast b/test/core/global.wast -index e40a305..8f8f25b 100644 +index e40a305f..8f8f25bb 100644 --- a/test/core/global.wast +++ b/test/core/global.wast @@ -328,10 +328,12 @@ @@ -168,7 +168,7 @@ index e40a305..8f8f25b 100644 (assert_invalid (module (global (import "test" "global-i32") i32) (global i32 (global.get 0) (global.get 0))) diff --git a/test/core/if.wast b/test/core/if.wast -index 2ea45f6..b6dd504 100644 +index 2ea45f6f..b6dd5044 100644 --- a/test/core/if.wast +++ b/test/core/if.wast @@ -527,11 +527,12 @@ @@ -199,7 +199,7 @@ index 2ea45f6..b6dd504 100644 (assert_malformed (module quote diff --git a/test/core/imports.wast b/test/core/imports.wast -index 69f76a0..a3844c6 100644 +index 69f76a0b..a3844c65 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -572,6 +572,7 @@ @@ -219,7 +219,7 @@ index 69f76a0..a3844c6 100644 ;; Syntax errors diff --git a/test/core/linking.wast b/test/core/linking.wast -index 994e0f4..d0bfb5f 100644 +index 994e0f49..d0bfb5f6 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -64,6 +64,7 @@ @@ -376,7 +376,7 @@ index 994e0f4..d0bfb5f 100644 (assert_return (invoke $Ms "get table[0]") (i32.const 0xdead)) +;) diff --git a/test/core/memory.wast b/test/core/memory.wast -index 1dd5b84..497b69f 100644 +index 1dd5b845..497b69fc 100644 --- a/test/core/memory.wast +++ b/test/core/memory.wast @@ -76,17 +76,17 @@ @@ -404,7 +404,7 @@ index 1dd5b84..497b69f 100644 (module diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast -index adb5cb7..590f626 100644 +index adb5cb78..590f6262 100644 --- a/test/core/ref_func.wast +++ b/test/core/ref_func.wast @@ -4,7 +4,8 @@ @@ -417,8 +417,65 @@ index adb5cb7..590f626 100644 (func $g (param $x i32) (result i32) (i32.add (local.get $x) (i32.const 1)) ) +diff --git a/test/core/table.wast b/test/core/table.wast +index 1b6afe9b..45dd1145 100644 +--- a/test/core/table.wast ++++ b/test/core/table.wast +@@ -8,16 +8,20 @@ + (module (table 0 65536 funcref)) + (module (table 0 0xffff_ffff funcref)) + ++(; TODO: wabt not unsupported gc yet + (module (table 1 (ref null func))) + (module (table 1 (ref null extern))) + (module (table 1 (ref null $t)) (type $t (func))) ++;) + + (module (table 0 funcref) (table 0 funcref)) + (module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) + ++(; TODO: wabt not unsupported gc yet + (module (table 0 funcref (ref.null func))) + (module (table 1 funcref (ref.null func))) + (module (table 1 (ref null func) (ref.null func))) ++;) + + (assert_invalid (module (elem (i32.const 0))) "unknown table") + (assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") +@@ -31,6 +35,7 @@ + "size minimum must not be greater than maximum" + ) + ++(; TODO: wabt not unsupported gc yet + (assert_invalid + (module quote "(table 0x1_0000_0000 funcref)") + "table size must be at most 2^32-1" +@@ -43,6 +48,7 @@ + (module quote "(table 0 0x1_0000_0000 funcref)") + "table size must be at most 2^32-1" + ) ++;) + + ;; Same as above but with i64 index types + +@@ -71,6 +77,7 @@ + (assert_invalid (module (elem (i32.const 0))) "unknown table") + (assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") + ++(; TODO: wabt not unsupported gc yet + (assert_invalid + (module (table 1 (ref null func) (i32.const 0))) + "type mismatch" +@@ -159,6 +166,7 @@ + ) + "type mismatch" + ) ++;) + + + ;; Duplicate table identifiers diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast -index 380e84e..f37e745 100644 +index 613fc529..abeca22c 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -14,11 +14,12 @@ @@ -728,8 +785,46 @@ index 380e84e..f37e745 100644 (table $t0 30 30 funcref) (table $t1 30 30 funcref) (elem (table $t1) (i32.const 2) func 3 1 4 1) +diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast +index e0872d78..6a84f239 100644 +--- a/test/core/table_grow.wast ++++ b/test/core/table_grow.wast +@@ -147,19 +147,20 @@ + ) + (register "grown-table" $Tgt) + (assert_return (invoke $Tgt "grow") (i32.const 1)) ;; now size is 2 +-(module $Tgit1 +- ;; imported table limits should match, because external table size is 2 now +- (table (export "table") (import "grown-table" "table") 2 funcref) +- (func (export "grow") (result i32) (table.grow (ref.null func) (i32.const 1))) +-) +-(register "grown-imported-table" $Tgit1) +-(assert_return (invoke $Tgit1 "grow") (i32.const 2)) ;; now size is 3 +-(module $Tgit2 +- ;; imported table limits should match, because external table size is 3 now +- (import "grown-imported-table" "table" (table 3 funcref)) +- (func (export "size") (result i32) (table.size)) +-) +-(assert_return (invoke $Tgit2 "size") (i32.const 3)) ++;; TODO: No dynnamic linking yet ++;; (module $Tgit1 ++;; ;; imported table limits should match, because external table size is 2 now ++;; (table (export "table") (import "grown-table" "table") 2 funcref) ++;; (func (export "grow") (result i32) (table.grow (ref.null func) (i32.const 1))) ++;; ) ++;; (register "grown-imported-table" $Tgit1) ++;; (assert_return (invoke $Tgit1 "grow") (i32.const 2)) ;; now size is 3 ++;; (module $Tgit2 ++;; ;; imported table limits should match, because external table size is 3 now ++;; (import "grown-imported-table" "table" (table 3 funcref)) ++;; (func (export "size") (result i32) (table.size)) ++;; ) ++;; (assert_return (invoke $Tgit2 "size") (i32.const 3)) + + + ;; Type errors diff --git a/test/core/table_init.wast b/test/core/table_init.wast -index 0b2d26f..bdab6a0 100644 +index 5c3679ab..76782794 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -14,11 +14,12 @@ @@ -749,8 +844,8 @@ index 0b2d26f..bdab6a0 100644 + (func (result i32) (i32.const 4)) ;; index 4 (table $t0 30 30 funcref) (table $t1 30 30 funcref) - (elem (table $t0) (i32.const 2) func 3 1 4 1) -@@ -72,11 +73,12 @@ + (table $t2 i64 30 30 funcref) +@@ -73,11 +74,12 @@ (module (type (func (result i32))) ;; type #0 @@ -767,8 +862,8 @@ index 0b2d26f..bdab6a0 100644 + (func (result i32) (i32.const 4)) ;; index 4 (table $t0 30 30 funcref) (table $t1 30 30 funcref) - (elem (table $t0) (i32.const 2) func 3 1 4 1) -@@ -130,11 +132,12 @@ + (table $t2 i64 30 30 funcref) +@@ -132,11 +134,12 @@ (module (type (func (result i32))) ;; type #0 @@ -785,8 +880,8 @@ index 0b2d26f..bdab6a0 100644 + (func (result i32) (i32.const 4)) ;; index 4 (table $t0 30 30 funcref) (table $t1 30 30 funcref) - (elem (table $t0) (i32.const 2) func 3 1 4 1) -@@ -196,11 +199,12 @@ + (table $t2 i64 30 30 funcref) +@@ -199,11 +202,12 @@ (module (type (func (result i32))) ;; type #0 @@ -803,8 +898,8 @@ index 0b2d26f..bdab6a0 100644 + (func (result i32) (i32.const 4)) ;; index 4 (table $t0 30 30 funcref) (table $t1 30 30 funcref) - (elem (table $t1) (i32.const 2) func 3 1 4 1) -@@ -254,11 +258,12 @@ + (table $t2 i64 30 30 funcref) +@@ -258,11 +262,12 @@ (module (type (func (result i32))) ;; type #0 @@ -821,8 +916,8 @@ index 0b2d26f..bdab6a0 100644 + (func (result i32) (i32.const 4)) ;; index 4 (table $t0 30 30 funcref) (table $t1 30 30 funcref) - (elem (table $t1) (i32.const 2) func 3 1 4 1) -@@ -312,11 +317,12 @@ + (table $t2 i64 30 30 funcref) +@@ -317,11 +322,12 @@ (module (type (func (result i32))) ;; type #0 @@ -839,9 +934,63 @@ index 0b2d26f..bdab6a0 100644 + (func (result i32) (i32.const 4)) ;; index 4 (table $t0 30 30 funcref) (table $t1 30 30 funcref) - (elem (table $t1) (i32.const 2) func 3 1 4 1) + (table $t2 i64 30 30 funcref) +@@ -384,11 +390,12 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ ;; aot mode does not support module linking ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (table $t2 i64 30 30 funcref) +@@ -443,11 +450,12 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ ;; aot mode does not support module linking ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (table $t2 i64 30 30 funcref) +@@ -502,11 +510,12 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ ;; aot mode does not support module linking ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (table $t2 i64 30 30 funcref) diff --git a/test/core/unreached-valid.wast b/test/core/unreached-valid.wast -index b7ebabf..4f2abfb 100644 +index b7ebabfd..4f2abfbf 100644 --- a/test/core/unreached-valid.wast +++ b/test/core/unreached-valid.wast @@ -46,6 +46,7 @@ diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 8254cc712..70a8b687c 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -375,7 +375,7 @@ function sightglass_test() function setup_wabt() { - WABT_VERSION=1.0.34 + WABT_VERSION=1.0.36 if [ ${WABT_BINARY_RELEASE} == "YES" ]; then echo "download a binary release and install" local WAT2WASM=${WORK_DIR}/wabt/out/gcc/Release/wat2wasm @@ -384,7 +384,7 @@ function setup_wabt() cosmopolitan) ;; linux) - WABT_PLATFORM=ubuntu + WABT_PLATFORM=ubuntu-20.04 ;; darwin) WABT_PLATFORM=macos-12 @@ -502,6 +502,8 @@ function spec_test() # Reset to commit: "Merge remote-tracking branch 'upstream/main' into merge2" git reset --hard 48e69f394869c55b7bbe14ac963c09f4605490b6 git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast test/core/data.wast + # Patch table64 extension + git checkout 940398cd4823522a9b36bec4984be4b153dedb81 -- test/core/call_indirect.wast test/core/table.wast test/core/table_copy.wast test/core/table_copy_mixed.wast test/core/table_fill.wast test/core/table_get.wast test/core/table_grow.wast test/core/table_init.wast test/core/table_set.wast test/core/table_size.wast git apply ../../spec-test-script/memory64_ignore_cases.patch || exit 1 elif [[ ${ENABLE_MULTI_MEMORY} == 1 ]]; then echo "checkout spec for multi memory proposal" @@ -511,7 +513,7 @@ function spec_test() pushd spec # Reset to commit: "Merge pull request #48 from backes/specify-memcpy-immediate-order" - git reset --hard 48e69f394869c55b7bbe14ac963c09f4605490b6 + git reset --hard fbc99efd7a788db300aec3dd62a14577ec404f1b git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast git apply ../../spec-test-script/multi_memory_ignore_cases.patch || exit 1 if [[ ${RUNNING_MODE} == "aot" ]]; then diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 2ab0462b2..ab98b0382 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -163,17 +163,10 @@ endif() # Enable LLVM if (NOT WAMR_BUILD_WITH_CUSTOM_LLVM) set (LLVM_SRC_ROOT "${PROJECT_SOURCE_DIR}/../core/deps/llvm") - if (WAMR_BUILD_PLATFORM STREQUAL "windows") - if (NOT EXISTS "${LLVM_SRC_ROOT}/win32build") - message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/win32build") - endif () - set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/win32build;${CMAKE_PREFIX_PATH}") - else() - if (NOT EXISTS "${LLVM_SRC_ROOT}/build") - message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") - endif () - set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") + if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") endif () + set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") endif () find_package(LLVM REQUIRED CONFIG) @@ -223,24 +216,14 @@ include_directories (${SHARED_DIR}/include enable_language (ASM) -if (NOT MINGW AND NOT MSVC) - if ((NOT DEFINED WAMR_BUILD_LIBC_WASI) AND (NOT DEFINED WAMR_BUILD_LIBC_UVWASI)) - set (WAMR_BUILD_LIBC_WASI 1) - endif () +if ((NOT DEFINED WAMR_BUILD_LIBC_WASI) AND (NOT DEFINED WAMR_BUILD_LIBC_UVWASI)) + # Enable WAMR_BUILD_LIBC_WASI if both are not set + set (WAMR_BUILD_LIBC_WASI 1) +endif () - if ((WAMR_BUILD_LIBC_WASI EQUAL 1) AND (WAMR_BUILD_LIBC_UVWASI EQUAL 1)) - message (WARNING "-- pick WAMR_BULID_LIBC_UVWASI when both are enabled") - set (WAMR_BUILD_LIBC_WASI 0) - endif () -else () - if (NOT DEFINED WAMR_BUILD_LIBC_UVWASI) - set (WAMR_BUILD_LIBC_UVWASI 1) - endif () - - if (WAMR_BUILD_LIBC_WASI EQUAL 1) - message (WARNING "-- don't accept WAMR_BUILD_LIBC_WASI=1 on MINGW or MSVC") - set (WAMR_BUILD_LIBC_WASI 0) - endif () +if ((WAMR_BUILD_LIBC_WASI EQUAL 1) AND (WAMR_BUILD_LIBC_UVWASI EQUAL 1)) + message (WARNING "-- pick WAMR_BULID_LIBC_UVWASI when both are enabled") + set (WAMR_BUILD_LIBC_WASI 0) endif () if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) @@ -308,6 +291,16 @@ if (WAMR_BUILD_LIBC_WASI EQUAL 1) include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake) endif () +if (WAMR_BUILD_LIBC_WASI EQUAL 1) + # Enable _Static_assert + set (CMAKE_C_STANDARD 11) + if (MSVC) + add_compile_options(/experimental:c11atomics) + endif() +else() + set (CMAKE_C_STANDARD 99) +endif() + if (WAMR_BUILD_LIB_PTHREAD EQUAL 1) include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake) endif () diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index b3e731e53..3efe344e6 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -142,9 +142,7 @@ print_help() printf(" with a runtime without the hardware bounds checks.\n"); printf(" --stack-bounds-checks=1/0 Enable or disable the bounds checks for native stack:\n"); printf(" if the option isn't set, the status is same as `--bounds-check`,\n"); - printf(" if the option is set:\n"); - printf(" (1) it is always enabled when `--bounds-checks` is enabled,\n"); - printf(" (2) else it is enabled/disabled according to the option value\n"); + printf(" if the option is set, the status is same as the option value\n"); printf(" --stack-usage= Generate a stack-usage file.\n"); printf(" Similarly to `clang -fstack-usage`.\n"); printf(" --format= Specifies the format of the output file\n"); @@ -164,6 +162,12 @@ print_help() printf(" GC is enabled\n"); printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n"); printf(" --enable-dump-call-stack Enable stack trace feature\n"); + printf(" --call-stack-features=\n"); + printf(" A comma-separated list of features when generating call stacks.\n"); + printf(" By default, all features are enabled. To disable all features,\n"); + printf(" provide an empty list (i.e. --call-stack-features=). This flag\n"); + printf(" only only takes effect when --enable-dump-call-stack is set.\n"); + printf(" Available features: bounds-checks, ip, func-idx, trap-ip, values.\n"); printf(" --enable-perf-profiling Enable function performance profiling\n"); printf(" --enable-memory-profiling Enable memory usage profiling\n"); printf(" --xip A shorthand of --enable-indirect-mode --disable-llvm-intrinsics\n"); @@ -202,6 +206,7 @@ print_help() printf(" --enable-linux-perf Enable linux perf support\n"); #endif printf(" --mllvm=