diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..0676cf741 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,35 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +version: 2 +updates: + +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + +- package-ecosystem: "docker" + directory: "/.devcontainer" + schedule: + interval: "weekly" + +- package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: "weekly" + +- package-ecosystem: "pip" + directory: "/build-scripts" + schedule: + interval: "weekly" + +- package-ecosystem: "pip" + directory: "/language-bindings/python/wasm-c-api" + schedule: + interval: "weekly" + +- package-ecosystem: "pip" + directory: "/language-bindings/python/wamr-api" + schedule: + interval: "weekly" diff --git a/.github/workflows/codeql_buildscript.sh b/.github/scripts/codeql_buildscript.sh similarity index 91% rename from .github/workflows/codeql_buildscript.sh rename to .github/scripts/codeql_buildscript.sh index 34e0ddd79..4bcabfe25 100755 --- a/.github/workflows/codeql_buildscript.sh +++ b/.github/scripts/codeql_buildscript.sh @@ -1,5 +1,10 @@ #!/usr/bin/env bash +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + sudo apt update sudo apt install -y build-essential cmake g++-multilib libgcc-11-dev lib32gcc-11-dev ccache ninja-build ccache @@ -101,6 +106,26 @@ if [[ $? != 0 ]]; then exit 1; fi +# build iwasm with exception handling enabled +cd ${WAMR_DIR}/product-mini/platforms/linux +rm -rf build && mkdir build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_EXCE_HANDLING=1 +make -j +if [[ $? != 0 ]]; then + echo "Failed to build iwasm with exception handling enabled!" + exit 1; +fi + +# build iwasm with memory64 enabled +cd ${WAMR_DIR}/product-mini/platforms/linux +rm -rf build && mkdir build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_MEMORY64=1 +make -j +if [[ $? != 0 ]]; then + echo "Failed to build iwasm with memory64 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 diff --git a/.github/scripts/codeql_fail_on_error.py b/.github/scripts/codeql_fail_on_error.py new file mode 100755 index 000000000..f150c38a2 --- /dev/null +++ b/.github/scripts/codeql_fail_on_error.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +import json +import sys +import os +import requests + + +def fetch_dismissed_alerts(repo_name, github_token): + headers = { + "Authorization": f"token {github_token}", + "Accept": "application/vnd.github.v3+json", + } + url = ( + f"https://api.github.com/repos/{repo_name}/code-scanning/alerts?state=dismissed" + ) + response = requests.get(url, headers=headers) + return response.json() # This assumes a successful API call + + +def parse_location(location): + path = location.get("physicalLocation", {}).get("artifactLocation", {}).get("uri") + start_line = location.get("physicalLocation", {}).get("region", {}).get("startLine") + column_range = ( + location.get("physicalLocation", {}).get("region", {}).get("startColumn"), + location.get("physicalLocation", {}).get("region", {}).get("endColumn"), + ) + return (path, start_line, column_range) + + +def is_dismissed(rule_id, path, start_line, column_range, dismissed_alerts): + for alert in dismissed_alerts: + alert_rule_id = alert.get("rule", {}).get("id") + alert_path = alert.get("location", {}).get("path") + alert_start_line = alert.get("location", {}).get("start_line") + alert_column_range = ( + alert.get("location", {}).get("start_column"), + alert.get("location", {}).get("end_column"), + ) + + if ( + rule_id == alert_rule_id + and path == alert_path + and start_line == alert_start_line + and column_range == alert_column_range + ): + return True + return False + + +# Return whether SARIF file contains error-level results +def codeql_sarif_contain_error(filename, dismissed_alerts): + has_error = False + + with open(filename, "r") as f: + s = json.load(f) + + for run in s.get("runs", []): + rules_metadata = run["tool"]["driver"]["rules"] + if not rules_metadata: + rules_metadata = run["tool"]["extensions"][0]["rules"] + + for res in run.get("results", []): + if "ruleIndex" in res: + rule_index = res["ruleIndex"] + elif "rule" in res and "index" in res["rule"]: + rule_index = res["rule"]["index"] + else: + continue + + # check whether it's dismissed before + rule_id = res["ruleId"] + path, start_line, column_range = parse_location(res["locations"][0]) + # the source code is from dependencies + if "_deps" in path: + continue + if is_dismissed(rule_id, path, start_line, column_range, dismissed_alerts): + print( + f"====== Finding a dismissed entry: {rule_id} at {path}:{start_line} is dismissed.======" + ) + print(res) + continue + + try: + rule_level = rules_metadata[rule_index]["defaultConfiguration"]["level"] + except IndexError as e: + print(e, rule_index, len(rules_metadata)) + else: + if rule_level == "error": + # very likely to be an actual error + if rules_metadata[rule_index]["properties"].get("precision") in [ + "high", + "very-high", + ]: + # the security severity is above medium(Common Vulnerability Scoring System (CVSS) >= 4.0) + if "security-severity" in rules_metadata[rule_index][ + "properties" + ] and ( + float( + rules_metadata[rule_index]["properties"][ + "security-severity" + ] + ) + > 4.0 + ): + print("====== Finding a likely error. ======") + print(res) + has_error = True + + return has_error + + +if __name__ == "__main__": + GITHUB_TOKEN = os.getenv("GITHUB_TOKEN") + GITHUB_REPOSITORY = os.getenv("GITHUB_REPOSITORY") + dismissed_alerts = fetch_dismissed_alerts(GITHUB_REPOSITORY, GITHUB_TOKEN) + + if codeql_sarif_contain_error(sys.argv[1], dismissed_alerts): + sys.exit(1) diff --git a/.github/scripts/fetch_and_compare_version.py b/.github/scripts/fetch_and_compare_version.py index ac206cade..ad9e53a0a 100644 --- a/.github/scripts/fetch_and_compare_version.py +++ b/.github/scripts/fetch_and_compare_version.py @@ -42,9 +42,12 @@ def fetch_version_from_code(): def fetch_latest_git_tag(): - list_tag_cmd = ( - 'git tag --list WAMR-*.*.* --sort=committerdate --format="%(refname:short)"' - ) + """ + Get the most recent tag from the HEAD, + if it's main branch, it should be the latest release tag. + if it's release/x.x.x branch, it should be the latest release tag of the branch. + """ + list_tag_cmd = "git describe --tags --abbrev=0 HEAD" p = subprocess.run(shlex.split(list_tag_cmd), capture_output=True, check=True) all_tags = p.stdout.decode().strip() diff --git a/.github/workflows/build_llvm_libraries.yml b/.github/workflows/build_llvm_libraries.yml index 18b90e568..67eaf614d 100644 --- a/.github/workflows/build_llvm_libraries.yml +++ b/.github/workflows/build_llvm_libraries.yml @@ -33,10 +33,16 @@ jobs: - name: checkout uses: actions/checkout@v4 - - name: install dependencies + - name: install dependencies for non macos-14 + if: inputs.os != 'macos-14' run: /usr/bin/env python3 -m pip install -r requirements.txt working-directory: build-scripts + - name: install dependencies for macos-14 + if: inputs.os == 'macos-14' + run: /usr/bin/env python3 -m pip install -r requirements.txt --break-system-packages + working-directory: build-scripts + - name: retrive the last commit ID id: get_last_commit run: echo "last_commit=$(GH_TOKEN=${{ secrets.GITHUB_TOKEN }} /usr/bin/env python3 ./build_llvm.py --llvm-ver)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/build_wamr_lldb.yml b/.github/workflows/build_wamr_lldb.yml index 3e1e10ffd..03474c53e 100644 --- a/.github/workflows/build_wamr_lldb.yml +++ b/.github/workflows/build_wamr_lldb.yml @@ -82,9 +82,7 @@ jobs: - name: install utils macos if: steps.lldb_build_cache.outputs.cache-hit != 'true' && contains(inputs.runner, 'macos') run: | - brew remove swig - brew install swig@4.1 cmake ninja libedit - brew link --overwrite swig@4.1 + brew install swig cmake ninja libedit sudo rm -rf /Library/Developer/CommandLineTools - name: install utils ubuntu diff --git a/.github/workflows/build_wamr_sdk.yml b/.github/workflows/build_wamr_sdk.yml index 69dbd7232..519bf9636 100644 --- a/.github/workflows/build_wamr_sdk.yml +++ b/.github/workflows/build_wamr_sdk.yml @@ -58,6 +58,12 @@ jobs: sudo rm ${basename} sudo mv wasi-sdk-* wasi-sdk + - name: download dependencies + run: | + cd ./wamr-app-framework/deps + ./download.sh + working-directory: wamr-sdk + - name: generate wamr-sdk release run: | cd ./wamr-app-framework/wamr-sdk diff --git a/.github/workflows/build_wamr_vscode_ext.yml b/.github/workflows/build_wamr_vscode_ext.yml index b91f054cf..322ba1c06 100644 --- a/.github/workflows/build_wamr_vscode_ext.yml +++ b/.github/workflows/build_wamr_vscode_ext.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/checkout@v4 - name: Use Node.js 16.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 16.x diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8656b326c..d4e7d05f2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -49,7 +49,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} @@ -64,9 +64,9 @@ jobs: # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - run: | - ./.github/workflows/codeql_buildscript.sh + ./.github/scripts/codeql_buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" upload: false @@ -95,14 +95,14 @@ jobs: output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif - name: Upload CodeQL results to code scanning - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 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@v3 + uses: actions/upload-artifact@v4 with: name: codeql-results path: ${{ steps.step1.outputs.sarif-output }} @@ -110,5 +110,8 @@ jobs: - name: Fail if an error is found run: | - ./.github/workflows/codeql_fail_on_error.py \ + ./.github/scripts/codeql_fail_on_error.py \ ${{ steps.step1.outputs.sarif-output }}/cpp.sarif + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/.github/workflows/codeql_fail_on_error.py b/.github/workflows/codeql_fail_on_error.py deleted file mode 100755 index 29791742b..000000000 --- a/.github/workflows/codeql_fail_on_error.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python3 - -import json -import sys - -# Return whether SARIF file contains error-level results -def codeql_sarif_contain_error(filename): - with open(filename, 'r') as f: - s = json.load(f) - - for run in s.get('runs', []): - rules_metadata = run['tool']['driver']['rules'] - if not rules_metadata: - rules_metadata = run['tool']['extensions'][0]['rules'] - - for res in run.get('results', []): - if 'ruleIndex' in res: - rule_index = res['ruleIndex'] - elif 'rule' in res and 'index' in res['rule']: - rule_index = res['rule']['index'] - else: - continue - try: - rule_level = rules_metadata[rule_index]['defaultConfiguration']['level'] - except IndexError as e: - print(e, rule_index, len(rules_metadata)) - else: - if rule_level == 'error': - return True - return False - -if __name__ == "__main__": - if codeql_sarif_contain_error(sys.argv[1]): - sys.exit(1) diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 481b06676..6b2a1a114 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -65,6 +65,7 @@ env: WASI_TEST_OPTIONS: "-s wasi_certification -w" WAMR_COMPILER_TEST_OPTIONS: "-s wamr_compiler -S -b -P" GC_TEST_OPTIONS: "-s spec -G -b -P" + MEMORY64_TEST_OPTIONS: "-s spec -W -b -P" jobs: build_llvm_libraries_on_ubuntu_2204: @@ -144,6 +145,7 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_TAIL_CALL=1", "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_MEMORY64=1", ] os: [ubuntu-22.04] platform: [android, linux] @@ -202,6 +204,21 @@ jobs: make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + # Memory64 only on CLASSIC INTERP mode, and only on 64-bit platform + - make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + platform: android + - make_options_run_mode: $AOT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" # Fast-JIT and Multi-Tier-JIT mode don't support android - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS platform: android @@ -372,14 +389,14 @@ jobs: cd /opt sudo wget ${{ matrix.wasi_sdk_release }} sudo tar -xzf wasi-sdk-*.tar.gz - sudo mv wasi-sdk-20.0 wasi-sdk + sudo ln -sf wasi-sdk-20.0 wasi-sdk - name: download and install wabt run: | cd /opt sudo wget ${{ matrix.wabt_release }} sudo tar -xzf wabt-1.0.31-*.tar.gz - sudo mv wabt-1.0.31 wabt + sudo ln -sf wabt-1.0.31 wabt - name: Get LLVM libraries id: retrieve_llvm_libs uses: actions/cache@v4 @@ -503,6 +520,7 @@ jobs: $THREADS_TEST_OPTIONS, $WASI_TEST_OPTIONS, $GC_TEST_OPTIONS, + $MEMORY64_TEST_OPTIONS, ] wasi_sdk_release: [ @@ -541,19 +559,30 @@ jobs: test_option: $GC_TEST_OPTIONS - running_mode: "multi-tier-jit" test_option: $GC_TEST_OPTIONS + # aot, fast-interp, fast-jit, llvm-jit, multi-tier-jit don't support Memory64 + - running_mode: "aot" + test_option: $MEMORY64_TEST_OPTIONS + - running_mode: "fast-interp" + test_option: $MEMORY64_TEST_OPTIONS + - running_mode: "fast-jit" + test_option: $MEMORY64_TEST_OPTIONS + - running_mode: "jit" + test_option: $MEMORY64_TEST_OPTIONS + - running_mode: "multi-tier-jit" + test_option: $MEMORY64_TEST_OPTIONS steps: - name: checkout uses: actions/checkout@v4 - name: Set-up OCaml uses: ocaml/setup-ocaml@v2 - if: matrix.test_option == '$GC_TEST_OPTIONS' + if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS' with: ocaml-compiler: 4.13 - name: Set-up Ocamlbuild - if: matrix.test_option == '$GC_TEST_OPTIONS' - run: opam install ocamlbuild dune + if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS' + run: opam install ocamlbuild dune menhir - name: download and install wasi-sdk if: matrix.test_option == '$WASI_TEST_OPTIONS' @@ -617,13 +646,13 @@ jobs: - name: run tests timeout-minutes: 30 - if: matrix.test_option != '$GC_TEST_OPTIONS' + if: matrix.test_option != '$GC_TEST_OPTIONS' && matrix.test_option != '$MEMORY64_TEST_OPTIONS' run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} working-directory: ./tests/wamr-test-suites - - name: run gc tests + - name: run gc or memory64 tests timeout-minutes: 20 - if: matrix.test_option == '$GC_TEST_OPTIONS' + if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS' run: | eval $(opam env) ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} diff --git a/.github/workflows/compilation_on_macos.yml b/.github/workflows/compilation_on_macos.yml index 4f59f2386..ec0943234 100644 --- a/.github/workflows/compilation_on_macos.yml +++ b/.github/workflows/compilation_on_macos.yml @@ -273,14 +273,14 @@ jobs: cd /opt sudo wget ${{ matrix.wasi_sdk_release }} sudo tar -xzf wasi-sdk-*.tar.gz - sudo mv wasi-sdk-20.0 wasi-sdk + sudo ln -sf wasi-sdk-20.0 wasi-sdk - name: download and install wabt run: | cd /opt sudo wget ${{ matrix.wabt_release }} sudo tar -xzf wabt-1.0.31-*.tar.gz - sudo mv wabt-1.0.31 wabt + sudo ln -sf wabt-1.0.31 wabt - name: Build Sample [basic] run: | @@ -346,7 +346,7 @@ jobs: cmake .. cmake --build . --config Release --parallel 4 working-directory: wamr-compiler - + - name: Build Sample [wasi-threads] run: | cd samples/wasi-threads @@ -378,4 +378,4 @@ jobs: cmake --build . --config Debug --parallel 4 ./iwasm wasm-apps/trap.wasm | grep "#" > call_stack.txt ./iwasm wasm-apps/trap.aot | grep "#" > call_stack_aot.txt - bash -x ../symbolicate.sh + bash -x ../symbolicate.sh diff --git a/.github/workflows/create_tag.yml b/.github/workflows/create_tag.yml index 27eee2acf..5480592a9 100644 --- a/.github/workflows/create_tag.yml +++ b/.github/workflows/create_tag.yml @@ -32,8 +32,22 @@ jobs: - name: prepare id: preparation run: | - # show latest 3 versions - git tag --list WAMR-*.*.* --sort=committerdate --format="%(refname:short)" | tail -n 3 + # show latest 3 versions on the branch that create release + # Set the initial commit to the head of the branch + commit="HEAD" + # + # Loop to get the three most recent tags + for i in {1..3} + do + # Get the most recent tag reachable from the current commit + tag=$(git describe --tags --abbrev=0 $commit) + + # Print the tag + echo "$tag" + + # Move to the commit before the found tag to find the next tag in the next iteration + commit=$(git rev-list -n 1 $tag^) + done # compare latest git tag and semantic version definition result=$(python3 ./.github/scripts/fetch_and_compare_version.py) echo "script result is ${result}" diff --git a/.github/workflows/nightly_run.yml b/.github/workflows/nightly_run.yml index 9d13e41e2..4b62d110a 100644 --- a/.github/workflows/nightly_run.yml +++ b/.github/workflows/nightly_run.yml @@ -8,7 +8,7 @@ on: types: - opened - synchronize - # running nightly pipeline if you're changing it + # running nightly pipeline if you're changing it # stress tests are run only in nightly at the moment, so running them in they are changed paths: - ".github/workflows/nightly_run.yml" @@ -54,7 +54,7 @@ jobs: with: os: "ubuntu-22.04" arch: "X86" - + build_wamrc: needs: [ @@ -65,7 +65,7 @@ jobs: matrix: include: - os: ubuntu-20.04 - llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} steps: - name: checkout uses: actions/checkout@v4 @@ -130,6 +130,7 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_TAIL_CALL=1", "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_MEMORY64=1", ] os: [ubuntu-20.04] platform: [android, linux] @@ -188,6 +189,21 @@ jobs: make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + # Memory64 only on CLASSIC INTERP mode, and only on 64-bit platform + - make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + platform: android + - make_options_run_mode: $AOT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" # Fast-JIT and Multi-Tier-JIT mode don't support android - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS platform: android @@ -271,6 +287,7 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_TAIL_CALL=1", "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_MEMORY64=1", ] exclude: # uncompatiable feature and platform @@ -299,6 +316,11 @@ jobs: # MINI_LOADER only on INTERP mode - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + # Memory64 only on CLASSIC INTERP mode + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" steps: - name: checkout uses: actions/checkout@v3 @@ -437,13 +459,13 @@ jobs: cd /opt sudo wget ${{ matrix.wasi_sdk_release }} sudo tar -xzf wasi-sdk-*.tar.gz - sudo mv wasi-sdk-20.0 wasi-sdk + sudo ln -sf wasi-sdk-20.0 wasi-sdk - name: download and install wabt run: | cd /opt sudo wget ${{ matrix.wabt_release }} sudo tar -xzf wabt-1.0.31-*.tar.gz - sudo mv wabt-1.0.31 wabt + sudo ln -sf wabt-1.0.31 wabt - name: Get LLVM libraries id: retrieve_llvm_libs @@ -621,7 +643,7 @@ jobs: sudo tar -xzf wasi-sdk-*.tar.gz sudo mv wasi-sdk-20.0 wasi-sdk - # It is a temporary solution until new wasi-sdk that includes bug fixes is released + # It is a temporary solution until new wasi-sdk that includes bug fixes is released - name: build wasi-libc from source if: matrix.test_option == '$WASI_TEST_OPTIONS' run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 8df86ddd0..0ffba05a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,11 @@ cmake_minimum_required (VERSION 3.0) +if(ESP_PLATFORM) + include (${COMPONENT_DIR}/build-scripts/esp-idf/wamr/CMakeLists.txt) + return() +endif() + project (iwasm) set (CMAKE_VERBOSE_MAKEFILE OFF) diff --git a/README.md b/README.md index d38a3208e..5a53536a5 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,8 @@ WebAssembly Micro Runtime (WAMR) is a lightweight standalone WebAssembly (Wasm) - [wasm-c-api](https://github.com/WebAssembly/wasm-c-api), ref to [document](doc/wasm_c_api.md) and [sample](samples/wasm-c-api) - [128-bit SIMD](https://github.com/WebAssembly/simd), ref to [samples/workload](samples/workload) - [Reference Types](https://github.com/WebAssembly/reference-types), ref to [document](doc/ref_types.md) and [sample](samples/ref-types) -- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) -- [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops), [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) -- [Multi-value](https://github.com/WebAssembly/multi-value), [Tail-call](https://github.com/WebAssembly/tail-call), [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) +- [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations), [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory), [Memory64](https://github.com/WebAssembly/memory64) +- [Tail-call](https://github.com/WebAssembly/tail-call), [Garbage Collection](https://github.com/WebAssembly/gc), [Exception Handling](https://github.com/WebAssembly/exception-handling) ### Supported architectures and platforms The WAMR VMcore supports the following architectures: @@ -68,6 +67,7 @@ The following platforms are supported, click each link below for how to build iw - [Port WAMR to a new platform](./doc/port_wamr.md) - [VS Code development container](./doc/devcontainer.md) - [Samples](./samples) and [Benchmarks](./tests/benchmarks) +- [End-user APIs documentation](https://bytecodealliance.github.io/wamr.dev/apis/) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 4569648a1..c3a957d33 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -134,7 +134,9 @@ endif () # Sanitizers -set(WAMR_BUILD_SANITIZER $ENV{WAMR_BUILD_SANITIZER}) +if (NOT DEFINED WAMR_BUILD_SANITIZER) + set(WAMR_BUILD_SANITIZER $ENV{WAMR_BUILD_SANITIZER}) +endif () if (NOT DEFINED WAMR_BUILD_SANITIZER) set(WAMR_BUILD_SANITIZER "") @@ -248,6 +250,15 @@ if (WAMR_BUILD_SHARED_MEMORY EQUAL 1) else () add_definitions (-DWASM_ENABLE_SHARED_MEMORY=0) 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.*") + message (FATAL_ERROR "-- Memory64 is only available on the 64-bit platform/target") + endif() + add_definitions (-DWASM_ENABLE_MEMORY64=1) + set (WAMR_DISABLE_HW_BOUND_CHECK 1) + message (" Memory64 memory enabled") +endif () if (WAMR_BUILD_THREAD_MGR EQUAL 1) message (" Thread manager enabled") endif () @@ -529,3 +540,25 @@ else () # Disable quick aot/jit entries for interp and fast-jit add_definitions (-DWASM_ENABLE_QUICK_AOT_ENTRY=0) endif () +if (WAMR_BUILD_AOT EQUAL 1) + if (NOT DEFINED WAMR_BUILD_AOT_INTRINSICS) + # Enable aot intrinsics by default + set (WAMR_BUILD_AOT_INTRINSICS 1) + endif () + if (WAMR_BUILD_AOT_INTRINSICS EQUAL 1) + add_definitions (-DWASM_ENABLE_AOT_INTRINSICS=1) + message (" AOT intrinsics enabled") + else () + add_definitions (-DWASM_ENABLE_AOT_INTRINSICS=0) + message (" AOT intrinsics disabled") + endif () +else () + # Disable aot intrinsics for interp, fast-jit and llvm-jit + add_definitions (-DWASM_ENABLE_AOT_INTRINSICS=0) +endif () +if (WAMR_BUILD_ALLOC_WITH_USAGE EQUAL 1) + add_definitions(-DWASM_MEM_ALLOC_WITH_USAGE=1) +endif() +if (NOT WAMR_BUILD_SANITIZER STREQUAL "") + message (" Sanitizer ${WAMR_BUILD_SANITIZER} enabled") +endif () diff --git a/core/config.h b/core/config.h index 616c1f6e7..5758132d7 100644 --- a/core/config.h +++ b/core/config.h @@ -415,7 +415,7 @@ #else #define DEFAULT_WASM_STACK_SIZE (12 * 1024) #endif -/* Min auxilliary stack size of each wasm thread */ +/* Min auxiliary stack size of each wasm thread */ #define WASM_THREAD_AUX_STACK_SIZE_MIN (256) /* Default/min native stack size of each app thread */ @@ -445,7 +445,29 @@ #endif /* Reserved bytes to the native thread stack boundary, throw native - stack overflow exception if the guard boudary is reached */ + * stack overflow exception if the guard boudary is reached + * + * WASM_STACK_GUARD_SIZE needs to be large enough for: + * + * - native functions + * w/o hw bound check, the overhead (aot_call_function etc) + the native + * function itself. as of writing this, the former is about 1000 bytes + * on macOS amd64. + * with hw bound check, theoretically, only needs to cover the logic to + * set up the jmp_buf stack. + * + * - aot runtime functions + * eg. aot_enlarge_memory. + * + * - w/o hw bound check, the intepreter loop + * + * - stack check wrapper functions generated by the aot compiler + * (--stack-bounds-checks=1) + * + * Note: on platforms with lazy function binding, don't forget to consider + * the symbol resolution overhead on the first call. For example, + * on Ubuntu amd64 20.04, it seems to consume about 1500 bytes. + */ #ifndef WASM_STACK_GUARD_SIZE #if WASM_ENABLE_UVWASI != 0 /* UVWASI requires larger native stack */ @@ -564,14 +586,31 @@ #endif /* Support registering quick AOT/JIT function entries of some func types - to speedup the calling process of invoking the AOT/JIT functions of + to speed up the calling process of invoking the AOT/JIT functions of these types from the host embedder */ #ifndef WASM_ENABLE_QUICK_AOT_ENTRY #define WASM_ENABLE_QUICK_AOT_ENTRY 1 #endif +/* Support AOT intrinsic functions which can be called from the AOT code + when `--disable-llvm-intrinsics` flag or + `--enable-builtin-intrinsics=` is used by wamrc to + generate the AOT file */ +#ifndef WASM_ENABLE_AOT_INTRINSICS +#define WASM_ENABLE_AOT_INTRINSICS 1 +#endif + +/* Disable memory64 by default */ +#ifndef WASM_ENABLE_MEMORY64 +#define WASM_ENABLE_MEMORY64 0 +#endif + #ifndef WASM_TABLE_MAX_SIZE #define WASM_TABLE_MAX_SIZE 1024 #endif +#ifndef WASM_MEM_ALLOC_WITH_USAGE +#define WASM_MEM_ALLOC_WITH_USAGE 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/aot/aot_intrinsic.c b/core/iwasm/aot/aot_intrinsic.c index 189b43b09..7b455cbb0 100644 --- a/core/iwasm/aot/aot_intrinsic.c +++ b/core/iwasm/aot/aot_intrinsic.c @@ -5,86 +5,6 @@ #include "aot_intrinsic.h" -typedef struct { - const char *llvm_intrinsic; - const char *native_intrinsic; - uint64 flag; -} aot_intrinsic; - -/* clang-format off */ -static const aot_intrinsic g_intrinsic_mapping[] = { - { "llvm.experimental.constrained.fadd.f32", "aot_intrinsic_fadd_f32", AOT_INTRINSIC_FLAG_F32_FADD }, - { "llvm.experimental.constrained.fadd.f64", "aot_intrinsic_fadd_f64", AOT_INTRINSIC_FLAG_F64_FADD }, - { "llvm.experimental.constrained.fsub.f32", "aot_intrinsic_fsub_f32", AOT_INTRINSIC_FLAG_F32_FSUB }, - { "llvm.experimental.constrained.fsub.f64", "aot_intrinsic_fsub_f64", AOT_INTRINSIC_FLAG_F64_FSUB }, - { "llvm.experimental.constrained.fmul.f32", "aot_intrinsic_fmul_f32", AOT_INTRINSIC_FLAG_F32_FMUL }, - { "llvm.experimental.constrained.fmul.f64", "aot_intrinsic_fmul_f64", AOT_INTRINSIC_FLAG_F64_FMUL }, - { "llvm.experimental.constrained.fdiv.f32", "aot_intrinsic_fdiv_f32", AOT_INTRINSIC_FLAG_F32_FDIV }, - { "llvm.experimental.constrained.fdiv.f64", "aot_intrinsic_fdiv_f64", AOT_INTRINSIC_FLAG_F64_FDIV }, - { "llvm.fabs.f32", "aot_intrinsic_fabs_f32", AOT_INTRINSIC_FLAG_F32_FABS }, - { "llvm.fabs.f64", "aot_intrinsic_fabs_f64", AOT_INTRINSIC_FLAG_F64_FABS }, - { "llvm.ceil.f32", "aot_intrinsic_ceil_f32", AOT_INTRINSIC_FLAG_F32_CEIL }, - { "llvm.ceil.f64", "aot_intrinsic_ceil_f64", AOT_INTRINSIC_FLAG_F64_CEIL }, - { "llvm.floor.f32", "aot_intrinsic_floor_f32", AOT_INTRINSIC_FLAG_F32_FLOOR }, - { "llvm.floor.f64", "aot_intrinsic_floor_f64", AOT_INTRINSIC_FLAG_F64_FLOOR }, - { "llvm.trunc.f32", "aot_intrinsic_trunc_f32", AOT_INTRINSIC_FLAG_F32_TRUNC }, - { "llvm.trunc.f64", "aot_intrinsic_trunc_f64", AOT_INTRINSIC_FLAG_F64_TRUNC }, - { "llvm.rint.f32", "aot_intrinsic_rint_f32", AOT_INTRINSIC_FLAG_F32_RINT }, - { "llvm.rint.f64", "aot_intrinsic_rint_f64", AOT_INTRINSIC_FLAG_F64_RINT }, - { "llvm.sqrt.f32", "aot_intrinsic_sqrt_f32", AOT_INTRINSIC_FLAG_F32_SQRT }, - { "llvm.sqrt.f64", "aot_intrinsic_sqrt_f64", AOT_INTRINSIC_FLAG_F64_SQRT }, - { "llvm.copysign.f32", "aot_intrinsic_copysign_f32", AOT_INTRINSIC_FLAG_F32_COPYSIGN }, - { "llvm.copysign.f64", "aot_intrinsic_copysign_f64", AOT_INTRINSIC_FLAG_F64_COPYSIGN }, - { "llvm.minnum.f32", "aot_intrinsic_fmin_f32", AOT_INTRINSIC_FLAG_F32_MIN }, - { "llvm.minnum.f64", "aot_intrinsic_fmin_f64", AOT_INTRINSIC_FLAG_F64_MIN }, - { "llvm.maxnum.f32", "aot_intrinsic_fmax_f32", AOT_INTRINSIC_FLAG_F32_MAX }, - { "llvm.maxnum.f64", "aot_intrinsic_fmax_f64", AOT_INTRINSIC_FLAG_F64_MAX }, - { "llvm.ctlz.i32", "aot_intrinsic_clz_i32", AOT_INTRINSIC_FLAG_I32_CLZ }, - { "llvm.ctlz.i64", "aot_intrinsic_clz_i64", AOT_INTRINSIC_FLAG_I64_CLZ }, - { "llvm.cttz.i32", "aot_intrinsic_ctz_i32", AOT_INTRINSIC_FLAG_I32_CTZ }, - { "llvm.cttz.i64", "aot_intrinsic_ctz_i64", AOT_INTRINSIC_FLAG_I64_CTZ }, - { "llvm.ctpop.i32", "aot_intrinsic_popcnt_i32", AOT_INTRINSIC_FLAG_I32_POPCNT }, - { "llvm.ctpop.i64", "aot_intrinsic_popcnt_i64", AOT_INTRINSIC_FLAG_I64_POPCNT }, - { "f64_convert_i32_s", "aot_intrinsic_i32_to_f64", AOT_INTRINSIC_FLAG_I32_TO_F64 }, - { "f64_convert_i32_u", "aot_intrinsic_u32_to_f64", AOT_INTRINSIC_FLAG_U32_TO_F64 }, - { "f32_convert_i32_s", "aot_intrinsic_i32_to_f32", AOT_INTRINSIC_FLAG_I32_TO_F32 }, - { "f32_convert_i32_u", "aot_intrinsic_u32_to_f32", AOT_INTRINSIC_FLAG_U32_TO_F32 }, - { "f64_convert_i64_s", "aot_intrinsic_i64_to_f64", AOT_INTRINSIC_FLAG_I32_TO_F64 }, - { "f64_convert_i64_u", "aot_intrinsic_u64_to_f64", AOT_INTRINSIC_FLAG_U64_TO_F64 }, - { "f32_convert_i64_s", "aot_intrinsic_i64_to_f32", AOT_INTRINSIC_FLAG_I64_TO_F32 }, - { "f32_convert_i64_u", "aot_intrinsic_u64_to_f32", AOT_INTRINSIC_FLAG_U64_TO_F32 }, - { "i32_trunc_f32_u", "aot_intrinsic_f32_to_u32", AOT_INTRINSIC_FLAG_F32_TO_U32 }, - { "i32_trunc_f32_s", "aot_intrinsic_f32_to_i32", AOT_INTRINSIC_FLAG_F32_TO_I32 }, - { "i32_trunc_f64_u", "aot_intrinsic_f64_to_u32", AOT_INTRINSIC_FLAG_F64_TO_U32 }, - { "i32_trunc_f64_s", "aot_intrinsic_f64_to_i32", AOT_INTRINSIC_FLAG_F64_TO_I32 }, - { "i64_trunc_f64_u", "aot_intrinsic_f64_to_u64", AOT_INTRINSIC_FLAG_F64_TO_U64 }, - { "i64_trunc_f32_s", "aot_intrinsic_f32_to_i64", AOT_INTRINSIC_FLAG_F32_TO_I64 }, - { "i64_trunc_f32_u", "aot_intrinsic_f32_to_u64", AOT_INTRINSIC_FLAG_F32_TO_U64 }, - { "i64_trunc_f64_s", "aot_intrinsic_f64_to_i64", AOT_INTRINSIC_FLAG_F64_TO_I64 }, - { "f32_demote_f64", "aot_intrinsic_f64_to_f32", AOT_INTRINSIC_FLAG_F64_TO_F32 }, - { "f64_promote_f32", "aot_intrinsic_f32_to_f64", AOT_INTRINSIC_FLAG_F32_TO_F64 }, - { "f32_cmp", "aot_intrinsic_f32_cmp", AOT_INTRINSIC_FLAG_F32_CMP }, - { "f64_cmp", "aot_intrinsic_f64_cmp", AOT_INTRINSIC_FLAG_F64_CMP }, - { "i32.const", NULL, AOT_INTRINSIC_FLAG_I32_CONST }, - { "i64.const", NULL, AOT_INTRINSIC_FLAG_I64_CONST }, - { "f32.const", NULL, AOT_INTRINSIC_FLAG_F32_CONST }, - { "f64.const", NULL, AOT_INTRINSIC_FLAG_F64_CONST }, - { "i64.div_s", "aot_intrinsic_i64_div_s", AOT_INTRINSIC_FLAG_I64_DIV_S}, - { "i32.div_s", "aot_intrinsic_i32_div_s", AOT_INTRINSIC_FLAG_I32_DIV_S}, - { "i32.div_u", "aot_intrinsic_i32_div_u", AOT_INTRINSIC_FLAG_I32_DIV_U}, - { "i32.rem_s", "aot_intrinsic_i32_rem_s", AOT_INTRINSIC_FLAG_I32_REM_S}, - { "i32.rem_u", "aot_intrinsic_i32_rem_u", AOT_INTRINSIC_FLAG_I32_REM_U}, - { "i64.div_u", "aot_intrinsic_i64_div_u", AOT_INTRINSIC_FLAG_I64_DIV_U}, - { "i64.rem_s", "aot_intrinsic_i64_rem_s", AOT_INTRINSIC_FLAG_I64_REM_S}, - { "i64.rem_u", "aot_intrinsic_i64_rem_u", AOT_INTRINSIC_FLAG_I64_REM_U}, - { "i64.or", "aot_intrinsic_i64_bit_or", AOT_INTRINSIC_FLAG_I64_BIT_OR}, - { "i64.and", "aot_intrinsic_i64_bit_and", AOT_INTRINSIC_FLAG_I64_BIT_AND}, -}; -/* clang-format on */ - -static const uint32 g_intrinsic_count = - sizeof(g_intrinsic_mapping) / sizeof(aot_intrinsic); - float32 aot_intrinsic_fadd_f32(float32 a, float32 b) { @@ -565,6 +485,88 @@ aot_intrinsic_i64_bit_and(uint64 l, uint64 r) return l & r; } +#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 + +typedef struct { + const char *llvm_intrinsic; + const char *native_intrinsic; + uint64 flag; +} aot_intrinsic; + +/* clang-format off */ +static const aot_intrinsic g_intrinsic_mapping[] = { + { "llvm.experimental.constrained.fadd.f32", "aot_intrinsic_fadd_f32", AOT_INTRINSIC_FLAG_F32_FADD }, + { "llvm.experimental.constrained.fadd.f64", "aot_intrinsic_fadd_f64", AOT_INTRINSIC_FLAG_F64_FADD }, + { "llvm.experimental.constrained.fsub.f32", "aot_intrinsic_fsub_f32", AOT_INTRINSIC_FLAG_F32_FSUB }, + { "llvm.experimental.constrained.fsub.f64", "aot_intrinsic_fsub_f64", AOT_INTRINSIC_FLAG_F64_FSUB }, + { "llvm.experimental.constrained.fmul.f32", "aot_intrinsic_fmul_f32", AOT_INTRINSIC_FLAG_F32_FMUL }, + { "llvm.experimental.constrained.fmul.f64", "aot_intrinsic_fmul_f64", AOT_INTRINSIC_FLAG_F64_FMUL }, + { "llvm.experimental.constrained.fdiv.f32", "aot_intrinsic_fdiv_f32", AOT_INTRINSIC_FLAG_F32_FDIV }, + { "llvm.experimental.constrained.fdiv.f64", "aot_intrinsic_fdiv_f64", AOT_INTRINSIC_FLAG_F64_FDIV }, + { "llvm.fabs.f32", "aot_intrinsic_fabs_f32", AOT_INTRINSIC_FLAG_F32_FABS }, + { "llvm.fabs.f64", "aot_intrinsic_fabs_f64", AOT_INTRINSIC_FLAG_F64_FABS }, + { "llvm.ceil.f32", "aot_intrinsic_ceil_f32", AOT_INTRINSIC_FLAG_F32_CEIL }, + { "llvm.ceil.f64", "aot_intrinsic_ceil_f64", AOT_INTRINSIC_FLAG_F64_CEIL }, + { "llvm.floor.f32", "aot_intrinsic_floor_f32", AOT_INTRINSIC_FLAG_F32_FLOOR }, + { "llvm.floor.f64", "aot_intrinsic_floor_f64", AOT_INTRINSIC_FLAG_F64_FLOOR }, + { "llvm.trunc.f32", "aot_intrinsic_trunc_f32", AOT_INTRINSIC_FLAG_F32_TRUNC }, + { "llvm.trunc.f64", "aot_intrinsic_trunc_f64", AOT_INTRINSIC_FLAG_F64_TRUNC }, + { "llvm.rint.f32", "aot_intrinsic_rint_f32", AOT_INTRINSIC_FLAG_F32_RINT }, + { "llvm.rint.f64", "aot_intrinsic_rint_f64", AOT_INTRINSIC_FLAG_F64_RINT }, + { "llvm.sqrt.f32", "aot_intrinsic_sqrt_f32", AOT_INTRINSIC_FLAG_F32_SQRT }, + { "llvm.sqrt.f64", "aot_intrinsic_sqrt_f64", AOT_INTRINSIC_FLAG_F64_SQRT }, + { "llvm.copysign.f32", "aot_intrinsic_copysign_f32", AOT_INTRINSIC_FLAG_F32_COPYSIGN }, + { "llvm.copysign.f64", "aot_intrinsic_copysign_f64", AOT_INTRINSIC_FLAG_F64_COPYSIGN }, + { "llvm.minnum.f32", "aot_intrinsic_fmin_f32", AOT_INTRINSIC_FLAG_F32_MIN }, + { "llvm.minnum.f64", "aot_intrinsic_fmin_f64", AOT_INTRINSIC_FLAG_F64_MIN }, + { "llvm.maxnum.f32", "aot_intrinsic_fmax_f32", AOT_INTRINSIC_FLAG_F32_MAX }, + { "llvm.maxnum.f64", "aot_intrinsic_fmax_f64", AOT_INTRINSIC_FLAG_F64_MAX }, + { "llvm.ctlz.i32", "aot_intrinsic_clz_i32", AOT_INTRINSIC_FLAG_I32_CLZ }, + { "llvm.ctlz.i64", "aot_intrinsic_clz_i64", AOT_INTRINSIC_FLAG_I64_CLZ }, + { "llvm.cttz.i32", "aot_intrinsic_ctz_i32", AOT_INTRINSIC_FLAG_I32_CTZ }, + { "llvm.cttz.i64", "aot_intrinsic_ctz_i64", AOT_INTRINSIC_FLAG_I64_CTZ }, + { "llvm.ctpop.i32", "aot_intrinsic_popcnt_i32", AOT_INTRINSIC_FLAG_I32_POPCNT }, + { "llvm.ctpop.i64", "aot_intrinsic_popcnt_i64", AOT_INTRINSIC_FLAG_I64_POPCNT }, + { "f64_convert_i32_s", "aot_intrinsic_i32_to_f64", AOT_INTRINSIC_FLAG_I32_TO_F64 }, + { "f64_convert_i32_u", "aot_intrinsic_u32_to_f64", AOT_INTRINSIC_FLAG_U32_TO_F64 }, + { "f32_convert_i32_s", "aot_intrinsic_i32_to_f32", AOT_INTRINSIC_FLAG_I32_TO_F32 }, + { "f32_convert_i32_u", "aot_intrinsic_u32_to_f32", AOT_INTRINSIC_FLAG_U32_TO_F32 }, + { "f64_convert_i64_s", "aot_intrinsic_i64_to_f64", AOT_INTRINSIC_FLAG_I32_TO_F64 }, + { "f64_convert_i64_u", "aot_intrinsic_u64_to_f64", AOT_INTRINSIC_FLAG_U64_TO_F64 }, + { "f32_convert_i64_s", "aot_intrinsic_i64_to_f32", AOT_INTRINSIC_FLAG_I64_TO_F32 }, + { "f32_convert_i64_u", "aot_intrinsic_u64_to_f32", AOT_INTRINSIC_FLAG_U64_TO_F32 }, + { "i32_trunc_f32_u", "aot_intrinsic_f32_to_u32", AOT_INTRINSIC_FLAG_F32_TO_U32 }, + { "i32_trunc_f32_s", "aot_intrinsic_f32_to_i32", AOT_INTRINSIC_FLAG_F32_TO_I32 }, + { "i32_trunc_f64_u", "aot_intrinsic_f64_to_u32", AOT_INTRINSIC_FLAG_F64_TO_U32 }, + { "i32_trunc_f64_s", "aot_intrinsic_f64_to_i32", AOT_INTRINSIC_FLAG_F64_TO_I32 }, + { "i64_trunc_f64_u", "aot_intrinsic_f64_to_u64", AOT_INTRINSIC_FLAG_F64_TO_U64 }, + { "i64_trunc_f32_s", "aot_intrinsic_f32_to_i64", AOT_INTRINSIC_FLAG_F32_TO_I64 }, + { "i64_trunc_f32_u", "aot_intrinsic_f32_to_u64", AOT_INTRINSIC_FLAG_F32_TO_U64 }, + { "i64_trunc_f64_s", "aot_intrinsic_f64_to_i64", AOT_INTRINSIC_FLAG_F64_TO_I64 }, + { "f32_demote_f64", "aot_intrinsic_f64_to_f32", AOT_INTRINSIC_FLAG_F64_TO_F32 }, + { "f64_promote_f32", "aot_intrinsic_f32_to_f64", AOT_INTRINSIC_FLAG_F32_TO_F64 }, + { "f32_cmp", "aot_intrinsic_f32_cmp", AOT_INTRINSIC_FLAG_F32_CMP }, + { "f64_cmp", "aot_intrinsic_f64_cmp", AOT_INTRINSIC_FLAG_F64_CMP }, + { "i32.const", NULL, AOT_INTRINSIC_FLAG_I32_CONST }, + { "i64.const", NULL, AOT_INTRINSIC_FLAG_I64_CONST }, + { "f32.const", NULL, AOT_INTRINSIC_FLAG_F32_CONST }, + { "f64.const", NULL, AOT_INTRINSIC_FLAG_F64_CONST }, + { "i64.div_s", "aot_intrinsic_i64_div_s", AOT_INTRINSIC_FLAG_I64_DIV_S}, + { "i32.div_s", "aot_intrinsic_i32_div_s", AOT_INTRINSIC_FLAG_I32_DIV_S}, + { "i32.div_u", "aot_intrinsic_i32_div_u", AOT_INTRINSIC_FLAG_I32_DIV_U}, + { "i32.rem_s", "aot_intrinsic_i32_rem_s", AOT_INTRINSIC_FLAG_I32_REM_S}, + { "i32.rem_u", "aot_intrinsic_i32_rem_u", AOT_INTRINSIC_FLAG_I32_REM_U}, + { "i64.div_u", "aot_intrinsic_i64_div_u", AOT_INTRINSIC_FLAG_I64_DIV_U}, + { "i64.rem_s", "aot_intrinsic_i64_rem_s", AOT_INTRINSIC_FLAG_I64_REM_S}, + { "i64.rem_u", "aot_intrinsic_i64_rem_u", AOT_INTRINSIC_FLAG_I64_REM_U}, + { "i64.or", "aot_intrinsic_i64_bit_or", AOT_INTRINSIC_FLAG_I64_BIT_OR}, + { "i64.and", "aot_intrinsic_i64_bit_and", AOT_INTRINSIC_FLAG_I64_BIT_AND}, +}; +/* clang-format on */ + +static const uint32 g_intrinsic_count = + sizeof(g_intrinsic_mapping) / sizeof(aot_intrinsic); + const char * aot_intrinsic_get_symbol(const char *llvm_intrinsic) { @@ -577,8 +579,6 @@ aot_intrinsic_get_symbol(const char *llvm_intrinsic) return NULL; } -#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 - static void add_intrinsic_capability(AOTCompContext *comp_ctx, uint64 flag) { diff --git a/core/iwasm/aot/aot_intrinsic.h b/core/iwasm/aot/aot_intrinsic.h index 2123058b9..6a456efda 100644 --- a/core/iwasm/aot/aot_intrinsic.h +++ b/core/iwasm/aot/aot_intrinsic.h @@ -287,10 +287,10 @@ aot_intrinsic_i64_bit_or(uint64 l, uint64 r); uint64 aot_intrinsic_i64_bit_and(uint64 l, uint64 r); +#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 const char * aot_intrinsic_get_symbol(const char *llvm_intrinsic); -#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 bool aot_intrinsic_check_capability(const AOTCompContext *comp_ctx, const char *llvm_intrinsic); diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 1634a8977..bdc80357f 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -16,6 +16,10 @@ #include "debug/jit_debug.h" #endif +#if WASM_ENABLE_LINUX_PERF != 0 +#include "aot_perf_map.h" +#endif + #define YMM_PLT_PREFIX "__ymm@" #define XMM_PLT_PREFIX "__xmm@" #define REAL_PLT_PREFIX "__real@" @@ -1430,9 +1434,20 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, read_uint64(buf, buf_end, init_expr_value); #if WASM_ENABLE_GC != 0 if (wasm_is_type_multi_byte_type(elem_type)) { - /* TODO: check ref_type */ - read_uint16(buf, buf_end, reftype.ref_ht_common.ref_type); - read_uint16(buf, buf_end, reftype.ref_ht_common.nullable); + uint16 ref_type, nullable; + read_uint16(buf, buf_end, ref_type); + if (elem_type != ref_type) { + set_error_buf(error_buf, error_buf_size, "invalid elem type"); + return false; + } + reftype.ref_ht_common.ref_type = (uint8)ref_type; + read_uint16(buf, buf_end, nullable); + if (nullable != 0 && nullable != 1) { + set_error_buf(error_buf, error_buf_size, + "invalid nullable value"); + return false; + } + reftype.ref_ht_common.nullable = (uint8)nullable; read_uint32(buf, buf_end, reftype.ref_ht_common.heap_type); } else @@ -1510,30 +1525,42 @@ fail: return false; } +static void +destroy_type(AOTType *type) +{ +#if WASM_ENABLE_GC != 0 + if (type->ref_count > 1) { + /* The type is referenced by other types + of current aot module */ + type->ref_count--; + return; + } + + if (type->type_flag == WASM_TYPE_FUNC) { + AOTFuncType *func_type = (AOTFuncType *)type; + if (func_type->ref_type_maps != NULL) { + bh_assert(func_type->ref_type_map_count > 0); + wasm_runtime_free(func_type->ref_type_maps); + } + } + else if (type->type_flag == WASM_TYPE_STRUCT) { + AOTStructType *struct_type = (AOTStructType *)type; + if (struct_type->ref_type_maps != NULL) { + bh_assert(struct_type->ref_type_map_count > 0); + wasm_runtime_free(struct_type->ref_type_maps); + } + } +#endif + wasm_runtime_free(type); +} + static void destroy_types(AOTType **types, uint32 count) { uint32 i; for (i = 0; i < count; i++) { - if (types[i]) { -#if WASM_ENABLE_GC != 0 - if (types[i]->type_flag == WASM_TYPE_FUNC) { - AOTFuncType *func_type = (AOTFuncType *)types[i]; - if (func_type->ref_type_maps != NULL) { - bh_assert(func_type->ref_type_map_count > 0); - wasm_runtime_free(func_type->ref_type_maps); - } - } - else if (types[i]->type_flag == WASM_TYPE_STRUCT) { - AOTStructType *struct_type = (AOTStructType *)types[i]; - if (struct_type->ref_type_maps != NULL) { - bh_assert(struct_type->ref_type_map_count > 0); - wasm_runtime_free(struct_type->ref_type_maps); - } - } -#endif - wasm_runtime_free(types[i]); + destroy_type(types[i]); } } wasm_runtime_free(types); @@ -1541,14 +1568,17 @@ destroy_types(AOTType **types, uint32 count) #if WASM_ENABLE_GC != 0 static void -init_base_type(AOTType *base_type, uint16 type_flag, bool is_sub_final, - uint32 parent_type_idx, uint16 rec_count, uint16 rec_idx) +init_base_type(AOTType *base_type, uint32 type_idx, uint16 type_flag, + bool is_sub_final, uint32 parent_type_idx, uint16 rec_count, + uint16 rec_idx) { base_type->type_flag = type_flag; + base_type->ref_count = 1; base_type->is_sub_final = is_sub_final; base_type->parent_type_idx = parent_type_idx; base_type->rec_count = rec_count; base_type->rec_idx = rec_idx; + base_type->rec_begin_type_idx = type_idx - rec_idx; } static bool @@ -1561,7 +1591,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, uint32 i, j; uint32 type_flag, param_cell_num, ret_cell_num; uint16 param_count, result_count, ref_type_map_count, rec_count, rec_idx; - bool is_sub_final; + bool is_equivalence_type, is_sub_final; uint32 parent_type_idx; WASMRefType ref_type; @@ -1575,12 +1605,31 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, /* Create each type */ for (i = 0; i < module->type_count; i++) { - buf = align_ptr(buf, 4); /* Read base type info */ read_uint16(buf, buf_end, type_flag); - read_uint16(buf, buf_end, is_sub_final); + + read_uint8(buf, buf_end, is_equivalence_type); + /* If there is an equivalence type, re-use it */ + if (is_equivalence_type) { + uint8 u8; + /* padding */ + read_uint8(buf, buf_end, u8); + (void)u8; + + read_uint32(buf, buf_end, j); + if (module->types[j]->ref_count == UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "wasm type's ref count too large"); + goto fail; + } + module->types[j]->ref_count++; + module->types[i] = module->types[j]; + continue; + } + + read_uint8(buf, buf_end, is_sub_final); read_uint32(buf, buf_end, parent_type_idx); read_uint16(buf, buf_end, rec_count); read_uint16(buf, buf_end, rec_idx); @@ -1605,7 +1654,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, types[i] = (AOTType *)func_type; - init_base_type((AOTType *)func_type, type_flag, is_sub_final, + init_base_type((AOTType *)func_type, i, type_flag, is_sub_final, parent_type_idx, rec_count, rec_idx); func_type->param_count = param_count; func_type->result_count = result_count; @@ -1711,7 +1760,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, offset = (uint32)offsetof(WASMStructObject, field_data); types[i] = (AOTType *)struct_type; - init_base_type((AOTType *)struct_type, type_flag, is_sub_final, + init_base_type((AOTType *)struct_type, i, type_flag, is_sub_final, parent_type_idx, rec_count, rec_idx); struct_type->field_count = field_count; struct_type->ref_type_map_count = ref_type_map_count; @@ -1797,7 +1846,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, types[i] = (AOTType *)array_type; - init_base_type((AOTType *)array_type, type_flag, is_sub_final, + init_base_type((AOTType *)array_type, i, type_flag, is_sub_final, parent_type_idx, rec_count, rec_idx); read_uint16(buf, buf_end, array_type->elem_flags); read_uint8(buf, buf_end, array_type->elem_type); @@ -1826,7 +1875,6 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, if (rec_count == 0) { bh_assert(rec_idx == 0); } - for (j = i - rec_idx; j <= i; j++) { AOTType *cur_type = module->types[j]; parent_type_idx = cur_type->parent_type_idx; @@ -1835,6 +1883,11 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, module->types[j]->parent_type = parent_type; module->types[j]->root_type = parent_type->root_type; + if (parent_type->inherit_depth == UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "parent type's inherit depth too large"); + goto fail; + } module->types[j]->inherit_depth = parent_type->inherit_depth + 1; } @@ -1852,7 +1905,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, AOTType *parent_type = module->types[parent_type_idx]; /* subtyping has been checked during compilation */ bh_assert(wasm_type_is_subtype_of( - module->types[j], parent_type, module->types, i)); + module->types[j], parent_type, module->types, i + 1)); (void)parent_type; } } @@ -3590,104 +3643,6 @@ fail: return ret; } -#if WASM_ENABLE_LINUX_PERF != 0 -struct func_info { - uint32 idx; - void *ptr; -}; - -static uint32 -get_func_size(const AOTModule *module, struct func_info *sorted_func_ptrs, - uint32 idx) -{ - uint32 func_sz; - - if (idx == module->func_count - 1) - func_sz = (uintptr_t)module->code + module->code_size - - (uintptr_t)(sorted_func_ptrs[idx].ptr); - else - func_sz = (uintptr_t)(sorted_func_ptrs[idx + 1].ptr) - - (uintptr_t)(sorted_func_ptrs[idx].ptr); - - return func_sz; -} - -static int -compare_func_ptrs(const void *f1, const void *f2) -{ - return (intptr_t)((struct func_info *)f1)->ptr - - (intptr_t)((struct func_info *)f2)->ptr; -} - -static struct func_info * -sort_func_ptrs(const AOTModule *module, char *error_buf, uint32 error_buf_size) -{ - uint64 content_len; - struct func_info *sorted_func_ptrs; - unsigned i; - - content_len = (uint64)sizeof(struct func_info) * module->func_count; - sorted_func_ptrs = loader_malloc(content_len, error_buf, error_buf_size); - if (!sorted_func_ptrs) - return NULL; - - for (i = 0; i < module->func_count; i++) { - sorted_func_ptrs[i].idx = i; - sorted_func_ptrs[i].ptr = module->func_ptrs[i]; - } - - qsort(sorted_func_ptrs, module->func_count, sizeof(struct func_info), - compare_func_ptrs); - - return sorted_func_ptrs; -} - -static bool -create_perf_map(const AOTModule *module, char *error_buf, uint32 error_buf_size) -{ - struct func_info *sorted_func_ptrs = NULL; - char perf_map_info[128] = { 0 }; - FILE *perf_map = NULL; - uint32 i; - pid_t pid = getpid(); - bool ret = false; - - sorted_func_ptrs = sort_func_ptrs(module, error_buf, error_buf_size); - if (!sorted_func_ptrs) - goto quit; - - snprintf(perf_map_info, 128, "/tmp/perf-%d.map", pid); - perf_map = fopen(perf_map_info, "w"); - if (!perf_map) { - LOG_WARNING("warning: can't create /tmp/perf-%d.map, because %s", pid, - strerror(errno)); - goto quit; - } - - for (i = 0; i < module->func_count; i++) { - memset(perf_map_info, 0, 128); - snprintf(perf_map_info, 128, "%lx %x aot_func#%u\n", - (uintptr_t)sorted_func_ptrs[i].ptr, - get_func_size(module, sorted_func_ptrs, i), - sorted_func_ptrs[i].idx); - - fwrite(perf_map_info, 1, strlen(perf_map_info), perf_map); - } - - LOG_VERBOSE("generate /tmp/perf-%d.map", pid); - ret = true; - -quit: - if (sorted_func_ptrs) - free(sorted_func_ptrs); - - if (perf_map) - fclose(perf_map); - - return ret; -} -#endif /* WASM_ENABLE_LINUX_PERF != 0*/ - static bool load_from_sections(AOTModule *module, AOTSection *sections, bool is_load_from_file_buf, char *error_buf, @@ -3878,7 +3833,7 @@ load_from_sections(AOTModule *module, AOTSection *sections, } static AOTModule * -create_module(char *error_buf, uint32 error_buf_size) +create_module(char *name, char *error_buf, uint32 error_buf_size) { AOTModule *module = loader_malloc(sizeof(AOTModule), error_buf, error_buf_size); @@ -3890,7 +3845,7 @@ create_module(char *error_buf, uint32 error_buf_size) module->module_type = Wasm_Module_AoT; - module->name = ""; + module->name = name; #if WASM_ENABLE_MULTI_MODULE != 0 module->import_module_list = &module->import_module_list_head; @@ -3926,7 +3881,7 @@ AOTModule * aot_load_from_sections(AOTSection *section_list, char *error_buf, uint32 error_buf_size) { - AOTModule *module = create_module(error_buf, error_buf_size); + AOTModule *module = create_module("", error_buf, error_buf_size); if (!module) return NULL; @@ -4172,7 +4127,7 @@ load(const uint8 *buf, uint32 size, AOTModule *module, char *error_buf, #if WASM_ENABLE_LINUX_PERF != 0 if (wasm_runtime_get_linux_perf()) - if (!create_perf_map(module, error_buf, error_buf_size)) + if (!aot_create_perf_map(module, error_buf, error_buf_size)) goto fail; #endif @@ -4182,10 +4137,10 @@ fail: } AOTModule * -aot_load_from_aot_file(const uint8 *buf, uint32 size, char *error_buf, - uint32 error_buf_size) +aot_load_from_aot_file(const uint8 *buf, uint32 size, const LoadArgs *args, + char *error_buf, uint32 error_buf_size) { - AOTModule *module = create_module(error_buf, error_buf_size); + AOTModule *module = create_module(args->name, error_buf, error_buf_size); if (!module) return NULL; @@ -4379,7 +4334,7 @@ aot_unload(AOTModule *module) } if (module->string_literal_ptrs) { - wasm_runtime_free(module->string_literal_ptrs); + wasm_runtime_free((void *)module->string_literal_ptrs); } } #endif diff --git a/core/iwasm/aot/aot_perf_map.c b/core/iwasm/aot/aot_perf_map.c new file mode 100644 index 000000000..22700dcdd --- /dev/null +++ b/core/iwasm/aot/aot_perf_map.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "aot_perf_map.h" +#include "bh_log.h" +#include "bh_platform.h" + +#if WASM_ENABLE_LINUX_PERF != 0 +struct func_info { + uint32 idx; + void *ptr; +}; + +static uint32 +get_func_size(const AOTModule *module, struct func_info *sorted_func_ptrs, + uint32 idx) +{ + uint32 func_sz; + + if (idx == module->func_count - 1) + func_sz = (uintptr_t)module->code + module->code_size + - (uintptr_t)(sorted_func_ptrs[idx].ptr); + else + func_sz = (uintptr_t)(sorted_func_ptrs[idx + 1].ptr) + - (uintptr_t)(sorted_func_ptrs[idx].ptr); + + return func_sz; +} + +static int +compare_func_ptrs(const void *f1, const void *f2) +{ + return (intptr_t)((struct func_info *)f1)->ptr + - (intptr_t)((struct func_info *)f2)->ptr; +} + +static struct func_info * +sort_func_ptrs(const AOTModule *module, char *error_buf, uint32 error_buf_size) +{ + uint64 content_len; + struct func_info *sorted_func_ptrs; + unsigned i; + + content_len = (uint64)sizeof(struct func_info) * module->func_count; + sorted_func_ptrs = wasm_runtime_malloc(content_len); + if (!sorted_func_ptrs) { + snprintf(error_buf, error_buf_size, + "allocate memory failed when creating perf map"); + return NULL; + } + + for (i = 0; i < module->func_count; i++) { + sorted_func_ptrs[i].idx = i; + sorted_func_ptrs[i].ptr = module->func_ptrs[i]; + } + + qsort(sorted_func_ptrs, module->func_count, sizeof(struct func_info), + compare_func_ptrs); + + return sorted_func_ptrs; +} + +bool +aot_create_perf_map(const AOTModule *module, char *error_buf, + uint32 error_buf_size) +{ + struct func_info *sorted_func_ptrs = NULL; + char perf_map_path[64] = { 0 }; + char perf_map_info[128] = { 0 }; + FILE *perf_map = NULL; + uint32 i; + pid_t pid = getpid(); + bool ret = false; + + sorted_func_ptrs = sort_func_ptrs(module, error_buf, error_buf_size); + if (!sorted_func_ptrs) + goto quit; + + snprintf(perf_map_path, sizeof(perf_map_path) - 1, "/tmp/perf-%d.map", pid); + perf_map = fopen(perf_map_path, "a"); + if (!perf_map) { + LOG_WARNING("warning: can't create /tmp/perf-%d.map, because %s", pid, + strerror(errno)); + goto quit; + } + + const char *module_name = aot_get_module_name((AOTModule *)module); + for (i = 0; i < module->func_count; i++) { + memset(perf_map_info, 0, 128); + if (strlen(module_name) > 0) + snprintf(perf_map_info, 128, "%lx %x [%s]#aot_func#%u\n", + (uintptr_t)sorted_func_ptrs[i].ptr, + get_func_size(module, sorted_func_ptrs, i), module_name, + sorted_func_ptrs[i].idx); + else + snprintf(perf_map_info, 128, "%lx %x aot_func#%u\n", + (uintptr_t)sorted_func_ptrs[i].ptr, + get_func_size(module, sorted_func_ptrs, i), + sorted_func_ptrs[i].idx); + + /* fwrite() is thread safe */ + fwrite(perf_map_info, 1, strlen(perf_map_info), perf_map); + } + + LOG_VERBOSE("write map information from %s into /tmp/perf-%d.map", + module_name, pid); + ret = true; + +quit: + if (sorted_func_ptrs) + wasm_runtime_free(sorted_func_ptrs); + + if (perf_map) + fclose(perf_map); + + return ret; +} +#endif /* WASM_ENABLE_LINUX_PERF != 0 */ \ No newline at end of file diff --git a/core/iwasm/aot/aot_perf_map.h b/core/iwasm/aot/aot_perf_map.h new file mode 100644 index 000000000..3e6583c5c --- /dev/null +++ b/core/iwasm/aot/aot_perf_map.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _AOT_PERF_MAP_H_ +#define _AOT_PERF_MAP_H_ + +#include "aot_runtime.h" + +bool +aot_create_perf_map(const AOTModule *module, char *error_buf, + uint32 error_buf_size); + +#endif /* _AOT_PERF_MAP_H_ */ \ No newline at end of file diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index c250f20a7..8ead3cd93 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -62,6 +62,7 @@ typedef struct { #define REG_AOT_TRACE_SYM() #endif +#if WASM_ENABLE_AOT_INTRINSICS != 0 #define REG_INTRINSIC_SYM() \ REG_SYM(aot_intrinsic_fabs_f32), \ REG_SYM(aot_intrinsic_fabs_f64), \ @@ -124,7 +125,10 @@ typedef struct { REG_SYM(aot_intrinsic_i32_div_s), \ REG_SYM(aot_intrinsic_i32_div_u), \ REG_SYM(aot_intrinsic_i32_rem_s), \ - REG_SYM(aot_intrinsic_i32_rem_u), \ + REG_SYM(aot_intrinsic_i32_rem_u), +#else +#define REG_INTRINSIC_SYM() +#endif #if WASM_ENABLE_STATIC_PGO != 0 #define REG_LLVM_PGO_SYM() \ @@ -139,6 +143,7 @@ typedef struct { REG_SYM(aot_array_init_with_data), \ REG_SYM(aot_create_func_obj), \ REG_SYM(aot_obj_is_instance_of), \ + REG_SYM(aot_func_type_is_super_of), \ REG_SYM(aot_rtt_type_new), \ REG_SYM(wasm_array_obj_copy), \ REG_SYM(wasm_array_obj_new), \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 1489b6260..2ec001713 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -880,7 +880,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, global_addr = module_inst->global_data + module->globals[global_idx].data_offset; *(uint32 *)global_addr = (uint32)aux_heap_base; - LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base); + LOG_VERBOSE("Reset __heap_base global to %" PRIu64, aux_heap_base); } else { /* Insert app heap before new page */ @@ -906,17 +906,19 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, LOG_VERBOSE("Memory instantiate:"); LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u", num_bytes_per_page, init_page_count, max_page_count); - LOG_VERBOSE(" data offset: %u, stack size: %d", module->aux_data_end, - module->aux_stack_size); - LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); + LOG_VERBOSE(" data offset: %" PRIu64 ", stack size: %d", + module->aux_data_end, module->aux_stack_size); + LOG_VERBOSE(" heap offset: %" PRIu64 ", heap size: %d\n", heap_offset, + heap_size); max_memory_data_size = (uint64)num_bytes_per_page * max_page_count; bh_assert(max_memory_data_size <= MAX_LINEAR_MEMORY_SIZE); (void)max_memory_data_size; - if (wasm_allocate_linear_memory(&p, is_shared_memory, num_bytes_per_page, - init_page_count, max_page_count, - &memory_data_size) + /* TODO: memory64 uses is_memory64 flag */ + if (wasm_allocate_linear_memory(&p, is_shared_memory, false, + num_bytes_per_page, init_page_count, + max_page_count, &memory_data_size) != BHT_OK) { set_error_buf(error_buf, error_buf_size, "allocate linear memory failed"); @@ -1069,8 +1071,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, /* Check memory data */ /* check offset since length might negative */ if (base_offset > memory_inst->memory_data_size) { - LOG_DEBUG("base_offset(%d) > memory_data_size(%d)", base_offset, - memory_inst->memory_data_size); + LOG_DEBUG("base_offset(%d) > memory_data_size(%" PRIu64 ")", + base_offset, memory_inst->memory_data_size); #if WASM_ENABLE_REF_TYPES != 0 set_error_buf(error_buf, error_buf_size, "out of bounds memory access"); @@ -1084,7 +1086,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, /* check offset + length(could be zero) */ length = data_seg->byte_count; if (base_offset + length > memory_inst->memory_data_size) { - LOG_DEBUG("base_offset(%d) + length(%d) > memory_data_size(%d)", + LOG_DEBUG("base_offset(%d) + length(%d) > memory_data_size(%" PRIu64 + ")", base_offset, length, memory_inst->memory_data_size); #if WASM_ENABLE_REF_TYPES != 0 set_error_buf(error_buf, error_buf_size, @@ -1718,6 +1721,7 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, bh_assert(table_init_data); + bh_assert(table_init_data->table_index < module_inst->table_count); table = module_inst->tables[table_init_data->table_index]; bh_assert(table); @@ -1725,8 +1729,9 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, bh_assert(table_data); wasm_runtime_get_table_inst_elem_type( - (WASMModuleInstanceCommon *)module_inst, i, &tbl_elem_type, - &tbl_elem_ref_type, &tbl_init_size, &tbl_max_size); + (WASMModuleInstanceCommon *)module_inst, + table_init_data->table_index, &tbl_elem_type, &tbl_elem_ref_type, + &tbl_init_size, &tbl_max_size); if (!wasm_elem_is_declarative(table_init_data->mode) && !wasm_reftype_is_subtype_of( @@ -2522,7 +2527,8 @@ aot_module_malloc_internal(AOTModuleInstance *module_inst, aot_set_exception(module_inst, "app heap corrupted"); } else { - LOG_WARNING("warning: allocate %u bytes memory failed", size); + LOG_WARNING("warning: allocate %" PRIu64 " bytes memory failed", + size); } return 0; } @@ -2805,7 +2811,7 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, } #if WASM_ENABLE_GC == 0 - func_idx = tbl_elem_val; + func_idx = (uint32)tbl_elem_val; #else func_idx = wasm_func_obj_get_func_idx_bound((WASMFuncObjectRef)tbl_elem_val); @@ -3362,39 +3368,49 @@ aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 length, } uint32 -aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx, - uint32 inc_entries, table_elem_type_t init_val) +aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 inc_size, + table_elem_type_t init_val) { - uint32 entry_count, i, orig_tbl_sz; AOTTableInstance *tbl_inst; + uint32 i, orig_size, total_size; tbl_inst = module_inst->tables[tbl_idx]; if (!tbl_inst) { return (uint32)-1; } - orig_tbl_sz = tbl_inst->cur_size; + orig_size = tbl_inst->cur_size; - if (!inc_entries) { - return orig_tbl_sz; + if (!inc_size) { + return orig_size; } - if (tbl_inst->cur_size > UINT32_MAX - inc_entries) { + if (tbl_inst->cur_size > UINT32_MAX - inc_size) { +#if WASM_ENABLE_SPEC_TEST == 0 + LOG_WARNING("table grow (%" PRIu32 "-> %" PRIu32 + ") failed because of integer overflow", + tbl_inst->cur_size, inc_size); +#endif return (uint32)-1; } - entry_count = tbl_inst->cur_size + inc_entries; - if (entry_count > tbl_inst->max_size) { + total_size = tbl_inst->cur_size + inc_size; + if (total_size > tbl_inst->max_size) { +#if WASM_ENABLE_SPEC_TEST == 0 + LOG_WARNING("table grow (%" PRIu32 "-> %" PRIu32 + ") failed because of over max size", + tbl_inst->cur_size, inc_size); +#endif return (uint32)-1; } /* fill in */ - for (i = 0; i < inc_entries; ++i) { + for (i = 0; i < inc_size; ++i) { tbl_inst->elems[tbl_inst->cur_size + i] = init_val; } - tbl_inst->cur_size = entry_count; - return orig_tbl_sz; + tbl_inst->cur_size = total_size; + return orig_size; } #endif /* WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */ @@ -3696,14 +3712,14 @@ aot_create_call_stack(struct WASMExecEnv *exec_env) frame.instance = module_inst; frame.module_offset = 0; - frame.func_index = cur_frame->func_index; - frame.func_offset = cur_frame->ip_offset; - frame.func_name_wp = - get_func_name_from_index(module_inst, cur_frame->func_index); + 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); if (cur_frame->func_index >= module->import_func_count) { uint32 aot_func_idx = - cur_frame->func_index - module->import_func_count; + (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]; } @@ -4473,6 +4489,22 @@ aot_obj_is_instance_of(AOTModuleInstance *module_inst, WASMObjectRef gc_obj, return wasm_obj_is_instance_of(gc_obj, type_index, types, type_count); } +bool +aot_func_type_is_super_of(AOTModuleInstance *module_inst, uint32 type_idx1, + uint32 type_idx2) +{ + AOTModule *aot_module = (AOTModule *)module_inst->module; + AOTType **types = aot_module->types; + + if (type_idx1 == type_idx2) + return true; + + bh_assert(types[type_idx1]->type_flag == WASM_TYPE_FUNC); + bh_assert(types[type_idx2]->type_flag == WASM_TYPE_FUNC); + return wasm_func_type_is_super_of((WASMFuncType *)types[type_idx1], + (WASMFuncType *)types[type_idx2]); +} + WASMRttTypeRef aot_rtt_type_new(AOTModuleInstance *module_inst, uint32 type_index) { @@ -4720,9 +4752,12 @@ aot_set_module_name(AOTModule *module, const char *name, char *error_buf, if (!name) return false; - module->name = - aot_const_str_set_insert((const uint8 *)name, strlen(name) + 1, module, - error_buf, error_buf_size); + module->name = aot_const_str_set_insert((const uint8 *)name, + (uint32)(strlen(name) + 1), module, +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + false, +#endif + error_buf, error_buf_size); return module->name != NULL; } diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 519c1edc1..63f8c872a 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -444,8 +444,8 @@ typedef struct LLVMProfileData_64 { * @return return AOT module loaded, NULL if failed */ AOTModule * -aot_load_from_aot_file(const uint8 *buf, uint32 size, char *error_buf, - uint32 error_buf_size); +aot_load_from_aot_file(const uint8 *buf, uint32 size, const LoadArgs *args, + char *error_buf, uint32 error_buf_size); /** * Load a AOT module from a specified AOT section list. @@ -752,6 +752,11 @@ bool aot_obj_is_instance_of(AOTModuleInstance *module_inst, WASMObjectRef gc_obj, uint32 type_index); +/* Whether func type1 is one of super types of func type2 */ +bool +aot_func_type_is_super_of(AOTModuleInstance *module_inst, uint32 type_idx1, + uint32 type_idx2); + WASMRttTypeRef aot_rtt_type_new(AOTModuleInstance *module_inst, uint32 type_index); diff --git a/core/iwasm/common/gc/gc_common.c b/core/iwasm/common/gc/gc_common.c index 80936f34a..99fca86d4 100644 --- a/core/iwasm/common/gc/gc_common.c +++ b/core/iwasm/common/gc/gc_common.c @@ -304,7 +304,12 @@ wasm_defined_type_equal(WASMType *const def_type1, WASMType *const def_type2, } #endif #if WASM_ENABLE_AOT != 0 - /* TODO */ + if (module->module_type == Wasm_Module_AoT) { + AOTModule *aot_module = (AOTModule *)module; + + types = aot_module->types; + type_count = aot_module->type_count; + } #endif bh_assert(types); diff --git a/core/iwasm/common/gc/gc_type.c b/core/iwasm/common/gc/gc_type.c index 0c9271c87..5ade1cb27 100644 --- a/core/iwasm/common/gc/gc_type.c +++ b/core/iwasm/common/gc/gc_type.c @@ -148,7 +148,7 @@ wasm_dump_func_type(const WASMFuncType *type) os_printf("] -> ["); - for (; i < type->param_count + type->result_count; i++) { + for (; i < (uint32)(type->param_count + type->result_count); i++) { if (wasm_is_type_multi_byte_type(type->types[i])) { bh_assert(j < type->ref_type_map_count); bh_assert(i == type->ref_type_maps[j].index); @@ -250,6 +250,51 @@ wasm_value_types_is_subtype_of(const uint8 *types1, return true; } +static bool +rec_ref_type_equal(const WASMRefType *ref_type1, const WASMRefType *ref_type2, + uint32 rec_begin_type_idx1, uint32 rec_begin_type_idx2, + uint32 rec_count, const WASMTypePtr *types, + uint32 type_count) +{ + uint32 type_idx1, type_idx2; + + if (!wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common) + || !wasm_is_refheaptype_typeidx(&ref_type2->ref_ht_common)) + return ref_type1->ref_ht_common.heap_type + == ref_type2->ref_ht_common.heap_type + ? true + : false; + + /* Now both ref types are type of (ref type_idx) */ + type_idx1 = ref_type1->ref_ht_typeidx.type_idx; + type_idx2 = ref_type2->ref_ht_typeidx.type_idx; + + if (type_idx1 >= rec_begin_type_idx1 + && type_idx1 < rec_begin_type_idx1 + rec_count) { + /* The converted iso-recursive types should be the same */ + bool ret = (type_idx2 >= rec_begin_type_idx2 + && type_idx2 < rec_begin_type_idx2 + rec_count + && type_idx1 - rec_begin_type_idx1 + == type_idx2 - rec_begin_type_idx2) + ? true + : false; + return ret; + } + else if (type_idx2 >= rec_begin_type_idx2 + && type_idx2 < rec_begin_type_idx2 + rec_count) { + /* The converted iso-recursive types should be the same */ + bool ret = (type_idx1 >= rec_begin_type_idx1 + && type_idx1 < rec_begin_type_idx1 + rec_count + && type_idx1 - rec_begin_type_idx1 + == type_idx2 - rec_begin_type_idx2) + ? true + : false; + return ret; + } + + return types[type_idx1] == types[type_idx2] ? true : false; +} + bool wasm_func_type_equal(const WASMFuncType *type1, const WASMFuncType *type2, const WASMTypePtr *types, uint32 type_count) @@ -264,7 +309,7 @@ wasm_func_type_equal(const WASMFuncType *type1, const WASMFuncType *type2, || type1->ref_type_map_count != type2->ref_type_map_count) return false; - for (i = 0; i < type1->param_count + type1->result_count; i++) { + for (i = 0; i < (uint32)(type1->param_count + type1->result_count); i++) { if (type1->types[i] != type2->types[i]) return false; @@ -277,9 +322,11 @@ wasm_func_type_equal(const WASMFuncType *type1, const WASMFuncType *type2, ref_type1 = type1->ref_type_maps[j].ref_type; ref_type2 = type2->ref_type_maps[j].ref_type; - if (!wasm_reftype_equal(ref_type1->ref_type, ref_type1, - ref_type2->ref_type, ref_type2, types, - type_count)) + + if (!rec_ref_type_equal( + ref_type1, ref_type2, type1->base_type.rec_begin_type_idx, + type2->base_type.rec_begin_type_idx, + type1->base_type.rec_count, types, type_count)) return false; j++; @@ -316,9 +363,11 @@ wasm_struct_type_equal(const WASMStructType *type1, const WASMStructType *type2, ref_type1 = type1->ref_type_maps[j].ref_type; ref_type2 = type2->ref_type_maps[j].ref_type; - if (!wasm_reftype_equal(ref_type1->ref_type, ref_type1, - ref_type2->ref_type, ref_type2, types, - type_count)) + + if (!rec_ref_type_equal( + ref_type1, ref_type2, type1->base_type.rec_begin_type_idx, + type2->base_type.rec_begin_type_idx, + type1->base_type.rec_count, types, type_count)) return false; j++; @@ -338,21 +387,67 @@ wasm_array_type_equal(const WASMArrayType *type1, const WASMArrayType *type2, if (type1->elem_flags != type2->elem_flags) return false; - return wasm_reftype_equal(type1->elem_type, type1->elem_ref_type, - type2->elem_type, type2->elem_ref_type, types, - type_count); + if (type1->elem_type != type2->elem_type) + return false; + + if (!wasm_is_type_multi_byte_type(type1->elem_type)) + return true; + + return rec_ref_type_equal(type1->elem_ref_type, type2->elem_ref_type, + type1->base_type.rec_begin_type_idx, + type2->base_type.rec_begin_type_idx, + type1->base_type.rec_count, types, type_count); } bool wasm_type_equal(const WASMType *type1, const WASMType *type2, const WASMTypePtr *types, uint32 type_count) { + uint32 rec_begin_type_idx1 = type1->rec_begin_type_idx; + uint32 rec_begin_type_idx2 = type2->rec_begin_type_idx; + uint32 parent_type_idx1, parent_type_idx2, rec_count; + if (type1 == type2) return true; - if (type1->type_flag != type2->type_flag) + if (!(type1->type_flag == type2->type_flag + && type1->is_sub_final == type2->is_sub_final + && type1->rec_count == type2->rec_count + && type1->rec_idx == type2->rec_idx)) return false; + rec_count = type1->rec_count; + + parent_type_idx1 = type1->parent_type_idx; + parent_type_idx2 = type2->parent_type_idx; + + if (parent_type_idx1 >= rec_begin_type_idx1 + && parent_type_idx1 < rec_begin_type_idx1 + rec_count) { + /* The converted iso-recursive types should be the same */ + if (!(parent_type_idx2 >= rec_begin_type_idx2 + && parent_type_idx2 < rec_begin_type_idx2 + rec_count + && parent_type_idx1 - rec_begin_type_idx1 + == parent_type_idx2 - rec_begin_type_idx2)) { + return false; + } + } + else if (parent_type_idx2 >= rec_begin_type_idx2 + && parent_type_idx2 < rec_begin_type_idx2 + rec_count) { + /* The converted iso-recursive types should be the same */ + if (!(parent_type_idx1 >= rec_begin_type_idx1 + && parent_type_idx1 < rec_begin_type_idx1 + rec_count + && parent_type_idx1 - rec_begin_type_idx1 + == parent_type_idx2 - rec_begin_type_idx2)) { + return false; + } + } + else if (type1->parent_type != type2->parent_type) { + /* The parent types should be same since they have been + normalized and equivalence types with different type + indexes are referring to a same WASMType */ + return false; + } + if (wasm_type_is_func_type(type1)) return wasm_func_type_equal((WASMFuncType *)type1, (WASMFuncType *)type2, types, type_count); @@ -399,7 +494,7 @@ wasm_func_type_is_subtype_of(const WASMFuncType *type1, } } - for (; i < type1->param_count + type1->result_count; i++) { + for (; i < (uint32)(type1->param_count + type1->result_count); i++) { if (wasm_is_type_multi_byte_type(type1->types[i])) { bh_assert(j1 < type1->ref_type_map_count); ref_type1 = type1->ref_type_maps[j1++].ref_type; @@ -653,12 +748,6 @@ wasm_reftype_struct_size(const WASMRefType *ref_type) return (uint32)sizeof(RefHeapType_Common); } -static bool -type_idx_equal(uint32 type_idx1, uint32 type_idx2) -{ - return (type_idx1 == type_idx2) ? true : false; -} - bool wasm_refheaptype_equal(const RefHeapType_Common *ref_heap_type1, const RefHeapType_Common *ref_heap_type2, @@ -673,8 +762,16 @@ wasm_refheaptype_equal(const RefHeapType_Common *ref_heap_type1, if (ref_heap_type1->heap_type != ref_heap_type2->heap_type) { if (wasm_is_refheaptype_typeidx(ref_heap_type1) && wasm_is_refheaptype_typeidx(ref_heap_type2)) { - return type_idx_equal(ref_heap_type1->heap_type, - ref_heap_type2->heap_type); + if (ref_heap_type1->heap_type == ref_heap_type2->heap_type) + return true; + else + /* the type_count may be 0 when called from reftype_equal */ + return ((uint32)ref_heap_type1->heap_type < type_count + && (uint32)ref_heap_type2->heap_type < type_count + && types[ref_heap_type1->heap_type] + == types[ref_heap_type2->heap_type]) + ? true + : false; } return false; } @@ -835,6 +932,13 @@ wasm_type_is_supers_of(const WASMType *type1, const WASMType *type2) return false; } +bool +wasm_func_type_is_super_of(const WASMFuncType *type1, const WASMFuncType *type2) +{ + return wasm_type_is_supers_of((const WASMType *)type1, + (const WASMType *)type2); +} + bool wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1, uint8 type2, const WASMRefType *ref_type2, @@ -914,14 +1018,15 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1, #endif else if (type1 == REF_TYPE_HT_NULLABLE) { if (wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common)) { + bh_assert((uint32)ref_type1->ref_ht_typeidx.type_idx < type_count); /* reftype1 is (ref null $t) */ if (type2 == REF_TYPE_HT_NULLABLE && ref_type2 != NULL && wasm_is_refheaptype_typeidx(&ref_type2->ref_ht_common)) { - return type_idx_equal(ref_type1->ref_ht_typeidx.type_idx, - ref_type2->ref_ht_typeidx.type_idx) - || wasm_type_is_supers_of( - types[ref_type2->ref_ht_typeidx.type_idx], - types[ref_type1->ref_ht_typeidx.type_idx]); + bh_assert((uint32)ref_type2->ref_ht_typeidx.type_idx + < type_count); + return wasm_type_is_supers_of( + types[ref_type2->ref_ht_typeidx.type_idx], + types[ref_type1->ref_ht_typeidx.type_idx]); } else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag == WASM_TYPE_STRUCT) @@ -963,16 +1068,17 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1, else if (type1 == REF_TYPE_HT_NON_NULLABLE) { bh_assert(ref_type1); if (wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common)) { + bh_assert((uint32)ref_type1->ref_ht_typeidx.type_idx < type_count); /* reftype1 is (ref $t) */ if ((type2 == REF_TYPE_HT_NULLABLE || type2 == REF_TYPE_HT_NON_NULLABLE) && ref_type2 != NULL && wasm_is_refheaptype_typeidx(&ref_type2->ref_ht_common)) { - return type_idx_equal(ref_type1->ref_ht_typeidx.type_idx, - ref_type2->ref_ht_typeidx.type_idx) - || wasm_type_is_supers_of( - types[ref_type2->ref_ht_typeidx.type_idx], - types[ref_type1->ref_ht_typeidx.type_idx]); + bh_assert((uint32)ref_type2->ref_ht_typeidx.type_idx + < type_count); + return wasm_type_is_supers_of( + types[ref_type2->ref_ht_typeidx.type_idx], + types[ref_type1->ref_ht_typeidx.type_idx]); } else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag == WASM_TYPE_STRUCT) { diff --git a/core/iwasm/common/gc/gc_type.h b/core/iwasm/common/gc/gc_type.h index 5b3840e45..919c8e501 100644 --- a/core/iwasm/common/gc/gc_type.h +++ b/core/iwasm/common/gc/gc_type.h @@ -47,6 +47,12 @@ wasm_func_type_is_subtype_of(const WASMFuncType *type1, const WASMFuncType *type2, const WASMTypePtr *types, uint32 type_count); +/* Whether func type1 is one of super types of func type2, + used for the func type check in call_indirect/call_ref opcodes */ +bool +wasm_func_type_is_super_of(const WASMFuncType *type1, + const WASMFuncType *type2); + /* Whether func type1's result types are subtype of func type2's result types */ bool diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 7aa4a563a..f19cb00e4 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -61,7 +61,7 @@ static union { * Implementation of wasm_application_execute_main() */ static bool -check_main_func_type(const WASMFuncType *type) +check_main_func_type(const WASMFuncType *type, bool is_memory64) { if (!(type->param_count == 0 || type->param_count == 2) || type->result_count > 1) { @@ -72,7 +72,8 @@ check_main_func_type(const WASMFuncType *type) if (type->param_count == 2 && !(type->types[0] == VALUE_TYPE_I32 - && type->types[1] == VALUE_TYPE_I32)) { + && type->types[1] + == (is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32))) { LOG_ERROR( "WASM execute application failed: invalid main function type.\n"); return false; @@ -94,14 +95,18 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) WASMFunctionInstanceCommon *func; WASMFuncType *func_type = NULL; WASMExecEnv *exec_env = NULL; - uint32 argc1 = 0, argv1[2] = { 0 }; + uint32 argc1 = 0, argv1[3] = { 0 }; uint32 total_argv_size = 0; uint64 total_size; uint64 argv_buf_offset = 0; int32 i; char *argv_buf, *p, *p_end; uint32 *argv_offsets, module_type; - bool ret, is_import_func = true; + bool ret, is_import_func = true, is_memory64 = false; +#if WASM_ENABLE_MEMORY64 != 0 + WASMModuleInstance *wasm_module_inst = (WASMModuleInstance *)module_inst; + is_memory64 = wasm_module_inst->memories[0]->is_memory64; +#endif exec_env = wasm_runtime_get_exec_env_singleton(module_inst); if (!exec_env) { @@ -187,7 +192,7 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) return false; } - if (!check_main_func_type(func_type)) { + if (!check_main_func_type(func_type, is_memory64)) { wasm_runtime_set_exception(module_inst, "invalid function type of main function"); return false; @@ -218,11 +223,21 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) p += strlen(argv[i]) + 1; } - argc1 = 2; argv1[0] = (uint32)argc; - /* TODO: memory64 uint64 when the memory idx is i64 */ - argv1[1] = - (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets); +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + argc1 = 3; + uint64 app_addr = + wasm_runtime_addr_native_to_app(module_inst, argv_offsets); + PUT_I64_TO_ADDR(&argv[1], app_addr); + } + else +#endif + { + argc1 = 2; + argv1[1] = (uint32)wasm_runtime_addr_native_to_app(module_inst, + argv_offsets); + } } ret = wasm_runtime_call_wasm(exec_env, func, argc1, argv1); @@ -563,8 +578,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name, is_anyref = true; } - if (wasm_is_type_multi_byte_type( - type->types[type->param_count + i])) { + if (wasm_is_type_multi_byte_type(type->types[i])) { WASMRefType *ref_type = ref_type_map->ref_type; if (wasm_is_refheaptype_common( &ref_type->ref_ht_common)) { diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 10ceb7583..456ce505e 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -2234,7 +2234,8 @@ quit: #endif /* WASM_ENABLE_WASM_CACHE != 0 */ wasm_module_t * -wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) +wasm_module_new_ex(wasm_store_t *store, const wasm_byte_vec_t *binary, + const LoadArgs *args) { char error_buf[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; @@ -2290,8 +2291,8 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) if (!module_ex->binary->data) goto free_binary; - module_ex->module_comm_rt = wasm_runtime_load( - (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, + module_ex->module_comm_rt = wasm_runtime_load_ex( + (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, args, error_buf, (uint32)sizeof(error_buf)); if (!(module_ex->module_comm_rt)) { LOG_ERROR("%s", error_buf); @@ -2337,6 +2338,14 @@ quit: return NULL; } +wasm_module_t * +wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + LoadArgs args = { 0 }; + args.name = ""; + return wasm_module_new_ex(store, binary, &args); +} + bool wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary) { @@ -3987,7 +3996,7 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_interp->cur_size) { return NULL; } - ref_idx = table_interp->elems[index]; + ref_idx = (uint32)table_interp->elems[index]; } #endif @@ -3998,7 +4007,7 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_aot->cur_size) { return NULL; } - ref_idx = table_aot->elems[index]; + ref_idx = (uint32)table_aot->elems[index]; } #endif diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index f96242332..53d248755 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -117,6 +117,9 @@ typedef struct WASMExecEnv { /* whether current thread is detached */ bool thread_is_detached; + + /* whether the aux stack is allocated */ + bool is_aux_stack_allocated; #endif #if WASM_ENABLE_GC != 0 diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 381e6b447..c49c1825a 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -29,24 +29,43 @@ static void *enlarge_memory_error_user_data; #if WASM_MEM_ALLOC_WITH_USER_DATA != 0 static void *allocator_user_data = NULL; -static void *(*malloc_func)(void *user_data, unsigned int size) = NULL; -static void *(*realloc_func)(void *user_data, void *ptr, - unsigned int size) = NULL; -static void (*free_func)(void *user_data, void *ptr) = NULL; -#else -static void *(*malloc_func)(unsigned int size) = NULL; -static void *(*realloc_func)(void *ptr, unsigned int size) = NULL; -static void (*free_func)(void *ptr) = NULL; #endif +static void *(*malloc_func)( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + mem_alloc_usage_t usage, +#endif +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + unsigned int size) = NULL; + +static void *(*realloc_func)( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + mem_alloc_usage_t usage, bool full_size_mmaped, +#endif +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr, unsigned int size) = NULL; + +static void (*free_func)( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + mem_alloc_usage_t usage, +#endif +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr) = NULL; + static unsigned int global_pool_size; -static uint32 +static uint64 align_as_and_cast(uint64 size, uint64 alignment) { uint64 aligned_size = (size + alignment - 1) & ~(alignment - 1); - return aligned_size > UINT32_MAX ? UINT32_MAX : (uint32)aligned_size; + return aligned_size; } static bool @@ -177,11 +196,14 @@ wasm_runtime_malloc_internal(unsigned int size) return mem_allocator_malloc(pool_allocator, size); } else if (memory_mode == MEMORY_MODE_ALLOCATOR) { -#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 - return malloc_func(allocator_user_data, size); -#else - return malloc_func(size); + return malloc_func( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + Alloc_For_Runtime, #endif +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + allocator_user_data, +#endif + size); } else { return os_malloc(size); @@ -201,11 +223,14 @@ wasm_runtime_realloc_internal(void *ptr, unsigned int size) } else if (memory_mode == MEMORY_MODE_ALLOCATOR) { if (realloc_func) -#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 - return realloc_func(allocator_user_data, ptr, size); -#else - return realloc_func(ptr, size); + return realloc_func( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + Alloc_For_Runtime, false, #endif +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + allocator_user_data, +#endif + ptr, size); else return NULL; } @@ -233,11 +258,14 @@ wasm_runtime_free_internal(void *ptr) mem_allocator_free(pool_allocator, ptr); } else if (memory_mode == MEMORY_MODE_ALLOCATOR) { -#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 - free_func(allocator_user_data, ptr); -#else - free_func(ptr); + free_func( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + Alloc_For_Runtime, #endif +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + allocator_user_data, +#endif + ptr); } else { os_free(ptr); @@ -286,6 +314,7 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm, { WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; WASMMemoryInstance *memory_inst; + uint64 max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE; bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode || module_inst_comm->module_type == Wasm_Module_AoT); @@ -299,9 +328,13 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm, goto fail; } +#if WASM_ENABLE_MEMORY64 != 0 + if (memory_inst->is_memory64) + max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; +#endif /* boundary overflow check */ - if (size > MAX_LINEAR_MEMORY_SIZE - || app_offset > MAX_LINEAR_MEMORY_SIZE - size) { + if (size > max_linear_memory_size + || app_offset > max_linear_memory_size - size) { goto fail; } @@ -324,7 +357,7 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm, uint64 app_str_offset) { WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; - uint64 app_end_offset; + uint64 app_end_offset, max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE; char *str, *str_end; bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode @@ -338,10 +371,14 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm, &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; +#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) + 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); @@ -364,6 +401,7 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm, WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; WASMMemoryInstance *memory_inst; uint8 *addr = (uint8 *)native_ptr; + uint64 max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE; bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode || module_inst_comm->module_type == Wasm_Module_AoT); @@ -377,8 +415,12 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm, goto fail; } +#if WASM_ENABLE_MEMORY64 != 0 + if (memory_inst->is_memory64) + max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; +#endif /* boundary overflow check */ - if (size > MAX_LINEAR_MEMORY_SIZE || (uintptr_t)addr > UINTPTR_MAX - size) { + if (size > max_linear_memory_size || (uintptr_t)addr > UINTPTR_MAX - size) { goto fail; } @@ -748,12 +790,36 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) goto return_func; } - bh_assert(total_size_new <= MAX_LINEAR_MEMORY_SIZE); + bh_assert(total_size_new + <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)); +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + if (!(memory_data_new = + realloc_func(Alloc_For_LinearMemory, full_size_mmaped, +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + NULL, +#endif + memory_data_old, total_size_new))) { + ret = false; + goto return_func; + } + if (heap_size > 0) { + if (mem_allocator_migrate(memory->heap_handle, + (char *)heap_data_old + + (memory_data_new - memory_data_old), + heap_size) + != 0) { + ret = false; + } + } + memory->heap_data = memory_data_new + (heap_data_old - memory_data_old); + memory->heap_data_end = memory->heap_data + heap_size; + memory->memory_data = memory_data_new; +#else if (full_size_mmaped) { #ifdef BH_PLATFORM_WINDOWS if (!os_mem_commit(memory->memory_data_end, - (uint32)(total_size_new - total_size_old), + (mem_offset_t)(total_size_new - total_size_old), MMAP_PROT_READ | MMAP_PROT_WRITE)) { ret = false; goto return_func; @@ -761,12 +827,12 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) #endif if (os_mprotect(memory->memory_data_end, - (uint32)(total_size_new - total_size_old), + (mem_offset_t)(total_size_new - total_size_old), MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { #ifdef BH_PLATFORM_WINDOWS os_mem_decommit(memory->memory_data_end, - (uint32)(total_size_new - total_size_old)); + (mem_offset_t)(total_size_new - total_size_old)); #endif ret = false; goto return_func; @@ -808,6 +874,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) os_writegsbase(memory_data_new); #endif } +#endif /* end of WASM_MEM_ALLOC_WITH_USAGE */ memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = total_page_count; @@ -888,15 +955,27 @@ wasm_deallocate_linear_memory(WASMMemoryInstance *memory_inst) #else map_size = 8 * (uint64)BH_GB; #endif + +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + (void)map_size; + free_func(Alloc_For_LinearMemory, +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + NULL, +#endif + memory_inst->memory_data); +#else wasm_munmap_linear_memory(memory_inst->memory_data, memory_inst->memory_data_size, map_size); +#endif + memory_inst->memory_data = NULL; } int wasm_allocate_linear_memory(uint8 **data, bool is_shared_memory, - uint64 num_bytes_per_page, uint64 init_page_count, - uint64 max_page_count, uint64 *memory_data_size) + bool is_memory64, uint64 num_bytes_per_page, + uint64 init_page_count, uint64 max_page_count, + uint64 *memory_data_size) { uint64 map_size, page_size; @@ -925,14 +1004,34 @@ wasm_allocate_linear_memory(uint8 **data, bool is_shared_memory, page_size = os_getpagesize(); *memory_data_size = init_page_count * num_bytes_per_page; - bh_assert(*memory_data_size <= MAX_LINEAR_MEMORY_SIZE); - align_as_and_cast(*memory_data_size, page_size); + +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + bh_assert(*memory_data_size <= MAX_LINEAR_MEM64_MEMORY_SIZE); + } + else +#endif + { + bh_assert(*memory_data_size <= MAX_LINEAR_MEMORY_SIZE); + } + *memory_data_size = align_as_and_cast(*memory_data_size, page_size); if (map_size > 0) { +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + (void)wasm_mmap_linear_memory; + if (!(*data = malloc_func(Alloc_For_LinearMemory, +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + NULL, +#endif + *memory_data_size))) { + return BHT_ERROR; + } +#else if (!(*data = wasm_mmap_linear_memory(map_size, *memory_data_size))) { return BHT_ERROR; } +#endif } return BHT_OK; -} \ No newline at end of file +} diff --git a/core/iwasm/common/wasm_memory.h b/core/iwasm/common/wasm_memory.h index 2ada2e618..a5dfefae9 100644 --- a/core/iwasm/common/wasm_memory.h +++ b/core/iwasm/common/wasm_memory.h @@ -64,8 +64,9 @@ wasm_deallocate_linear_memory(WASMMemoryInstance *memory_inst); int wasm_allocate_linear_memory(uint8 **data, bool is_shared_memory, - uint64 num_bytes_per_page, uint64 init_page_count, - uint64 max_page_count, uint64 *memory_data_size); + bool is_memory64, uint64 num_bytes_per_page, + uint64 init_page_count, uint64 max_page_count, + uint64 *memory_data_size); #ifdef __cplusplus } diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 14b295ee7..394dfd2b5 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -84,9 +84,9 @@ compare_type_with_signautre(uint8 type, const char signature) if ('r' == signature #if WASM_ENABLE_GC != 0 #if WASM_ENABLE_STRINGREF != 0 - && (type >= REF_TYPE_STRINGVIEWITER && type <= REF_TYPE_FUNCREF) + && (type >= REF_TYPE_STRINGVIEWITER && type <= REF_TYPE_NULLFUNCREF) #else - && (type >= REF_TYPE_NULLREF && type <= REF_TYPE_FUNCREF) + && (type >= REF_TYPE_HT_NULLABLE && type <= REF_TYPE_NULLFUNCREF) #endif #else && type == VALUE_TYPE_EXTERNREF diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index b3ee45091..d93bb682e 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -65,7 +65,7 @@ #if WASM_ENABLE_MULTI_MODULE != 0 /** * A safety insurance to prevent - * circular depencies which leads stack overflow + * circular dependencies which leads stack overflow * try to break early */ typedef struct LoadingModule { @@ -275,11 +275,11 @@ decode_insn(uint8 *insn) buffer, sizeof(buffer), runtime_address); +#if 0 /* Print current instruction */ - /* os_printf("%012" PRIX64 " ", runtime_address); puts(buffer); - */ +#endif return instruction.length; } @@ -564,8 +564,20 @@ wasm_runtime_exec_env_check(WASMExecEnv *exec_env) && exec_env->wasm_stack.top <= exec_env->wasm_stack.top_boundary; } -bool -wasm_runtime_init() +#if defined(OS_THREAD_MUTEX_INITIALIZER) +/** + * lock for wasm_runtime_init/wasm_runtime_full_init and runtime_ref_count + * Note: if the platform has mutex initializer, we use a global lock to + * lock the operations of runtime init/full_init, otherwise when there are + * operations happening simultaneously in multiple threads, developer + * must create the lock by himself, and use it to lock the operations + */ +static korp_mutex runtime_lock = OS_THREAD_MUTEX_INITIALIZER; +#endif +static int32 runtime_ref_count = 0; + +static bool +wasm_runtime_init_internal() { if (!wasm_runtime_memory_init(Alloc_With_System_Allocator, NULL)) return false; @@ -578,8 +590,32 @@ wasm_runtime_init() return true; } -void -wasm_runtime_destroy() +bool +wasm_runtime_init() +{ + bool ret = true; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&runtime_lock); +#endif + + bh_assert(runtime_ref_count >= 0); + if (runtime_ref_count == 0) { + ret = wasm_runtime_init_internal(); + } + if (ret) { + runtime_ref_count++; + } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&runtime_lock); +#endif + + return ret; +} + +static void +wasm_runtime_destroy_internal() { #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 wasm_externref_map_destroy(); @@ -640,6 +676,24 @@ wasm_runtime_destroy() wasm_runtime_memory_destroy(); } +void +wasm_runtime_destroy() +{ +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&runtime_lock); +#endif + + bh_assert(runtime_ref_count > 0); + runtime_ref_count--; + if (runtime_ref_count == 0) { + wasm_runtime_destroy_internal(); + } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&runtime_lock); +#endif +} + RunningMode wasm_runtime_get_default_running_mode(void) { @@ -662,8 +716,8 @@ wasm_runtime_get_gc_heap_size_default(void) } #endif -bool -wasm_runtime_full_init(RuntimeInitArgs *init_args) +static bool +wasm_runtime_full_init_internal(RuntimeInitArgs *init_args) { if (!wasm_runtime_memory_init(init_args->mem_alloc_type, &init_args->mem_alloc_option)) @@ -725,6 +779,30 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args) return true; } +bool +wasm_runtime_full_init(RuntimeInitArgs *init_args) +{ + bool ret = true; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&runtime_lock); +#endif + + bh_assert(runtime_ref_count >= 0); + if (runtime_ref_count == 0) { + ret = wasm_runtime_full_init_internal(init_args); + } + if (ret) { + runtime_ref_count++; + } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&runtime_lock); +#endif + + return ret; +} + void wasm_runtime_set_log_level(log_level_t level) { @@ -965,7 +1043,7 @@ wasm_runtime_register_module_internal(const char *module_name, /* module hasn't been registered */ node = runtime_malloc(sizeof(WASMRegisteredModule), NULL, NULL, 0); if (!node) { - LOG_DEBUG("malloc WASMRegisteredModule failed. SZ=%d", + LOG_DEBUG("malloc WASMRegisteredModule failed. SZ=%zu", sizeof(WASMRegisteredModule)); return false; } @@ -1255,11 +1333,15 @@ register_module_with_null_name(WASMModuleCommon *module_common, char *error_buf, } WASMModuleCommon * -wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, - uint32 error_buf_size) +wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args, + char *error_buf, uint32 error_buf_size) { WASMModuleCommon *module_common = NULL; + if (!args) { + return NULL; + } + if (get_package_type(buf, size) == Wasm_Module_Bytecode) { #if WASM_ENABLE_INTERP != 0 module_common = @@ -1267,13 +1349,13 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, #if WASM_ENABLE_MULTI_MODULE != 0 true, #endif - error_buf, error_buf_size); + args, error_buf, error_buf_size); #endif } else if (get_package_type(buf, size) == Wasm_Module_AoT) { #if WASM_ENABLE_AOT != 0 module_common = (WASMModuleCommon *)aot_load_from_aot_file( - buf, size, error_buf, error_buf_size); + buf, size, args, error_buf, error_buf_size); #endif } else { @@ -1289,10 +1371,21 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, LOG_DEBUG("WASM module load failed"); return NULL; } + + /*TODO: use file name as name and register with name? */ return register_module_with_null_name(module_common, error_buf, error_buf_size); } +WASMModuleCommon * +wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, + uint32 error_buf_size) +{ + LoadArgs args = { 0 }; + args.name = ""; + return wasm_runtime_load_ex(buf, size, &args, error_buf, error_buf_size); +} + WASMModuleCommon * wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot, char *error_buf, uint32 error_buf_size) @@ -1702,7 +1795,7 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env) wasm_runtime_dump_module_inst_mem_consumption(module_inst_common); wasm_runtime_dump_exec_env_mem_consumption(exec_env); os_printf("\nTotal memory consumption of module, module inst and " - "exec env: %u\n", + "exec env: %" PRIu64 "\n", total_size); os_printf("Total interpreter stack used: %u\n", exec_env->max_wasm_stack_used); @@ -3668,7 +3761,7 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); typedef void (*NativeRawFuncPtr)(WASMExecEnv *, uint64 *); NativeRawFuncPtr invoke_native_raw = (NativeRawFuncPtr)func_ptr; - uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size; + uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size, arg_i64; uint32 *argv_src = argv, i, argc1, ptr_len; uint32 arg_i32; bool ret = false; @@ -3692,9 +3785,11 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_FUNCREF: #endif { - /* TODO: memory64 the data type of ptr_len and argc depends on - * mem idx type */ *(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[i + 1] == '*') { /* param is a pointer */ @@ -3724,9 +3819,49 @@ 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 + { + PUT_I64_TO_ADDR((uint32 *)argv_dst, + GET_I64_FROM_ADDR(argv_src)); + argv_src += 2; + arg_i64 = *argv_dst; + if (signature) { + /* TODO: memory64 pointer with length need a new symbol + * to represent type i64, with '~' still represent i32 + * length */ + if (signature[i + 1] == '*') { + /* param is a pointer */ + if (signature[i + 2] == '~') + /* pointer with length followed */ + ptr_len = *argv_src; + else + /* pointer without length followed */ + ptr_len = 1; + + if (!wasm_runtime_validate_app_addr(module, arg_i64, + (uint64)ptr_len)) + goto fail; + + *argv_dst = (uint64)wasm_runtime_addr_app_to_native( + module, arg_i64); + } + else if (signature[i + 1] == '$') { + /* param is a string */ + if (!wasm_runtime_validate_app_str_addr(module, + arg_i64)) + goto fail; + + *argv_dst = (uint64)wasm_runtime_addr_app_to_native( + module, arg_i64); + } + } + break; + } +#endif case VALUE_TYPE_F64: bh_memcpy_s(argv_dst, sizeof(uint64), argv_src, sizeof(uint32) * 2); @@ -3855,6 +3990,9 @@ 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; } @@ -4117,8 +4255,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { arg_i32 = *argv_src++; - /* TODO: memory64 the data type of ptr_len and argc depends on - * mem idx type */ if (signature) { if (signature[i + 1] == '*') { /* param is a pointer */ @@ -4494,8 +4630,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { arg_i32 = *argv++; - /* TODO: memory64 the data type of ptr_len and argc depends on - * mem idx type */ if (signature) { if (signature[i + 1] == '*') { /* param is a pointer */ @@ -4811,8 +4945,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { arg_i32 = *argv_src++; arg_i64 = arg_i32; - /* TODO: memory64 the data type of ptr_len and argc depends on - * mem idx type */ + /* 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[i + 1] == '*') { /* param is a pointer */ @@ -4840,6 +4976,7 @@ 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 @@ -4847,6 +4984,47 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; } case VALUE_TYPE_I64: +#if WASM_ENABLE_MEMORY64 != 0 + { + arg_i64 = GET_I64_FROM_ADDR(argv_src); + argv_src += 2; + if (signature) { + /* TODO: memory64 pointer with length need a new symbol + * to represent type i64, with '~' still represent i32 + * length */ + if (signature[i + 1] == '*') { + /* param is a pointer */ + if (signature[i + 2] == '~') + /* pointer with length followed */ + ptr_len = *argv_src; + else + /* pointer without length followed */ + ptr_len = 1; + + if (!wasm_runtime_validate_app_addr(module, arg_i64, + (uint64)ptr_len)) + goto fail; + + arg_i64 = (uint64)wasm_runtime_addr_app_to_native( + module, arg_i64); + } + else if (signature[i + 1] == '$') { + /* param is a string */ + if (!wasm_runtime_validate_app_str_addr(module, + arg_i64)) + goto fail; + + arg_i64 = (uint64)wasm_runtime_addr_app_to_native( + module, arg_i64); + } + } + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = arg_i64; + else + stacks[n_stacks++] = arg_i64; + break; + } +#endif #if WASM_ENABLE_GC != 0 case REF_TYPE_FUNCREF: case REF_TYPE_EXTERNREF: @@ -5325,6 +5503,7 @@ wasm_externref_set_cleanup(WASMModuleInstanceCommon *module_inst, if (lookup_user_data.found) { void *key = (void *)(uintptr_t)lookup_user_data.externref_idx; ExternRefMapNode *node = bh_hash_map_find(externref_map, key); + bh_assert(node); node->cleanup = extern_obj_cleanup; ok = true; } @@ -6337,6 +6516,7 @@ wasm_runtime_load_depended_module(const WASMModuleCommon *parent_module, bool ret = false; uint8 *buffer = NULL; uint32 buffer_size = 0; + LoadArgs args = { 0 }; /* check the registered module list of the parent */ sub_module = wasm_runtime_search_sub_module(parent_module, sub_module_name); @@ -6376,23 +6556,25 @@ wasm_runtime_load_depended_module(const WASMModuleCommon *parent_module, if (!ret) { LOG_DEBUG("read the file of %s failed", sub_module_name); set_error_buf_v(parent_module, error_buf, error_buf_size, - "unknown import", sub_module_name); + "unknown import %s", sub_module_name); goto delete_loading_module; } if (get_package_type(buffer, buffer_size) != parent_module->module_type) { LOG_DEBUG("moudle %s type error", sub_module_name); - goto delete_loading_module; + goto destroy_file_buffer; } + + args.name = (char *)sub_module_name; if (get_package_type(buffer, buffer_size) == Wasm_Module_Bytecode) { #if WASM_ENABLE_INTERP != 0 - sub_module = (WASMModuleCommon *)wasm_load(buffer, buffer_size, false, - error_buf, error_buf_size); + sub_module = (WASMModuleCommon *)wasm_load( + buffer, buffer_size, false, &args, error_buf, error_buf_size); #endif } else if (get_package_type(buffer, buffer_size) == Wasm_Module_AoT) { #if WASM_ENABLE_AOT != 0 sub_module = (WASMModuleCommon *)aot_load_from_aot_file( - buffer, buffer_size, error_buf, error_buf_size); + buffer, buffer_size, &args, error_buf, error_buf_size); #endif } if (!sub_module) { @@ -6487,7 +6669,7 @@ wasm_runtime_sub_module_instantiate(WASMModuleCommon *module, sub_module_inst_list_node = loader_malloc(sizeof(WASMSubModInstNode), error_buf, error_buf_size); if (!sub_module_inst_list_node) { - LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ:%d", + LOG_DEBUG("Malloc WASMSubModInstNode failed, SZ: %zu", sizeof(WASMSubModInstNode)); if (sub_module_inst) wasm_runtime_deinstantiate_internal(sub_module_inst, false); @@ -6625,4 +6807,4 @@ wasm_runtime_get_module_name(wasm_module_t module) #endif return ""; -} \ No newline at end of file +} diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index aaf04ec2f..62c35473a 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -373,7 +373,7 @@ typedef struct WASMModuleCommon { /* The following uint8[1] member is a dummy just to indicate some module_type dependent members follow. - Typically it should be accessed by casting to the corresponding + Typically, it should be accessed by casting to the corresponding actual module_type dependent structure, not via this member. */ uint8 module_data[1]; } WASMModuleCommon; @@ -389,7 +389,7 @@ typedef struct WASMModuleInstanceCommon { /* The following uint8[1] member is a dummy just to indicate some module_type dependent members follow. - Typically it should be accessed by casting to the corresponding + Typically, it should be accessed by casting to the corresponding actual module_type dependent structure, not via this member. */ uint8 module_inst_data[1]; } WASMModuleInstanceCommon; diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 81ad9b7a3..5c257742a 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -330,7 +330,7 @@ aot_gen_commit_values(AOTCompFrame *frame) if (!p->dirty) continue; - n = p - frame->lp; + n = (uint32)(p - frame->lp); /* Commit reference flag */ if (comp_ctx->enable_gc) { @@ -432,7 +432,7 @@ aot_gen_commit_values(AOTCompFrame *frame) continue; p->dirty = 0; - n = p - frame->lp; + n = (uint32)(p - frame->lp); /* Commit values */ switch (p->type) { @@ -538,7 +538,7 @@ aot_gen_commit_values(AOTCompFrame *frame) /* Clear reference flags for unused stack slots. */ for (p = frame->sp; p < end; p++) { bh_assert(!p->ref); - n = p - frame->lp; + n = (uint32)(p - frame->lp); /* Commit reference flag. */ if (p->ref != p->committed_ref - 1) { @@ -621,7 +621,7 @@ aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip) } if (commit_sp) { - n = sp - frame->lp; + n = (uint32)(sp - frame->lp); value = I32_CONST(offset_of_local(comp_ctx, n)); if (!value) { aot_set_last_error("llvm build const failed"); @@ -966,7 +966,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) location = dwarf_gen_location( comp_ctx, func_ctx, (frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code); - LLVMSetCurrentDebugLocation2(comp_ctx->builder, location); + if (location != NULL) { + LLVMSetCurrentDebugLocation2(comp_ctx->builder, location); + } #endif switch (opcode) { @@ -3450,16 +3452,6 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; } - case SIMD_i32x4_narrow_i64x2_s: - case SIMD_i32x4_narrow_i64x2_u: - { - if (!aot_compile_simd_i32x4_narrow_i64x2( - comp_ctx, func_ctx, - SIMD_i32x4_narrow_i64x2_s == opcode)) - return false; - break; - } - case SIMD_i32x4_extend_low_i16x8_s: case SIMD_i32x4_extend_high_i16x8_s: { @@ -3499,16 +3491,6 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; } - case SIMD_i32x4_add_sat_s: - case SIMD_i32x4_add_sat_u: - { - if (!aot_compile_simd_i32x4_saturate( - comp_ctx, func_ctx, V128_ADD, - opcode == SIMD_i32x4_add_sat_s)) - return false; - break; - } - case SIMD_i32x4_sub: { if (!aot_compile_simd_i32x4_arith(comp_ctx, func_ctx, @@ -3517,16 +3499,6 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; } - case SIMD_i32x4_sub_sat_s: - case SIMD_i32x4_sub_sat_u: - { - if (!aot_compile_simd_i32x4_saturate( - comp_ctx, func_ctx, V128_SUB, - opcode == SIMD_i32x4_add_sat_s)) - return false; - break; - } - case SIMD_i32x4_mul: { if (!aot_compile_simd_i32x4_arith(comp_ctx, func_ctx, @@ -3563,13 +3535,6 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; } - case SIMD_i32x4_avgr_u: - { - if (!aot_compile_simd_i32x4_avgr_u(comp_ctx, func_ctx)) - return false; - break; - } - case SIMD_i32x4_extmul_low_i16x8_s: case SIMD_i32x4_extmul_high_i16x8_s: { @@ -3726,13 +3691,6 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; } - case SIMD_f32x4_round: - { - if (!aot_compile_simd_f32x4_round(comp_ctx, func_ctx)) - return false; - break; - } - case SIMD_f32x4_sqrt: { if (!aot_compile_simd_f32x4_sqrt(comp_ctx, func_ctx)) @@ -3786,13 +3744,6 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) break; } - case SIMD_f64x2_round: - { - if (!aot_compile_simd_f64x2_round(comp_ctx, func_ctx)) - return false; - break; - } - case SIMD_f64x2_sqrt: { if (!aot_compile_simd_f64x2_sqrt(comp_ctx, func_ctx)) diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 52637686f..426171984 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -484,15 +484,15 @@ static uint32 get_func_type_size(AOTCompContext *comp_ctx, AOTFuncType *func_type) { #if WASM_ENABLE_GC != 0 - /* type flag + is_sub_final + parent_type_idx + rec_count + rec_idx + param - * count + result count - * + ref_type_map_count + types + context of ref_type_map */ + /* type flag + equivalence type flag + is_sub_final + parent_type_idx + + rec_count + rec_idx + param count + result count + + ref_type_map_count + types + context of ref_type_map */ if (comp_ctx->enable_gc) { uint32 size = 0; /* type flag */ size += sizeof(func_type->base_type.type_flag); - /* is_sub_final */ + /* equivalence type flag + is_sub_final */ size += sizeof(uint16); /* parent_type_idx */ size += sizeof(func_type->base_type.parent_type_idx); @@ -529,12 +529,12 @@ static uint32 get_struct_type_size(AOTCompContext *comp_ctx, AOTStructType *struct_type) { uint32 size = 0; - /* type flag + is_sub_final + parent_type_idx + rec_count + rec_idx + field - * count + fields */ + /* type flag + equivalence type flag + is_sub_final + parent_type_idx + + rec_count + rec_idx + field count + fields */ /* type flag */ size += sizeof(struct_type->base_type.type_flag); - /* is_sub_final */ + /* equivalence type flag + is_sub_final */ size += sizeof(uint16); /* parent_type_idx */ size += sizeof(struct_type->base_type.parent_type_idx); @@ -558,12 +558,12 @@ static uint32 get_array_type_size(AOTCompContext *comp_ctx, AOTArrayType *array_type) { uint32 size = 0; - /* type flag + is_sub_final + parent_type_idx + rec_count + rec_idx + - elem_flags + elem_type + elem_ref_type */ + /* type flag + equivalence type flag + is_sub_final + parent_type_idx + + rec_count + rec_idx + elem_flags + elem_type + elem_ref_type */ /* type flag */ size += sizeof(array_type->base_type.type_flag); - /* is_sub_final */ + /* equivalence type flag + is_sub_final */ size += sizeof(uint16); /* parent_type_idx (u32) */ size += sizeof(array_type->base_type.parent_type_idx); @@ -597,7 +597,22 @@ get_type_info_size(AOTCompContext *comp_ctx, AOTCompData *comp_data) #if WASM_ENABLE_GC != 0 if (comp_ctx->enable_gc) { for (i = 0; i < comp_data->type_count; i++) { + uint32 j; + size = align_uint(size, 4); + + /* Emit simple info if there is an equivalence type */ + for (j = 0; j < i; j++) { + if (comp_data->types[j] == comp_data->types[i]) { + /* type_flag (2 bytes) + equivalence type flag (1 byte) + + padding (1 byte) + equivalence type index */ + size += 8; + break; + } + } + if (j < i) + continue; + if (comp_data->types[i]->type_flag == WASM_TYPE_FUNC) size += get_func_type_size(comp_ctx, (AOTFuncType *)comp_data->types[i]); @@ -2093,13 +2108,32 @@ aot_emit_type_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, #if WASM_ENABLE_GC != 0 if (comp_ctx->enable_gc) { - int32 idx; AOTType **types = comp_data->types; + int32 idx; + uint32 j; for (i = 0; i < comp_data->type_count; i++) { offset = align_uint(offset, 4); + + /* Emit simple info if there is an equivalence type */ + for (j = 0; j < i; j++) { + if (types[j] == types[i]) { + EMIT_U16(types[i]->type_flag); + /* equivalence type flag is true */ + EMIT_U8(1); + EMIT_U8(0); + /* equivalence type index */ + EMIT_U32(j); + break; + } + } + if (j < i) + continue; + EMIT_U16(types[i]->type_flag); - EMIT_U16(types[i]->is_sub_final); + /* equivalence type flag is false */ + EMIT_U8(0); + EMIT_U8(types[i]->is_sub_final); EMIT_U32(types[i]->parent_type_idx); EMIT_U16(types[i]->rec_count); @@ -2593,7 +2627,7 @@ aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, if (comp_ctx->enable_gc) { /* emit func_local_ref_flag arrays for both import and AOTed funcs */ AOTFuncType *func_type; - uint32 j, local_ref_flags_cell_num; + uint32 j, local_ref_flags_cell_num, paddings; for (i = 0; i < comp_data->import_func_count; i++) { func_type = comp_data->import_funcs[i].func_type; @@ -2603,6 +2637,8 @@ aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, local_ref_flags_cell_num += wasm_value_type_cell_num_internal( func_type->types[j], comp_ctx->pointer_size); } + paddings = + local_ref_flags_cell_num < 2 ? 2 - local_ref_flags_cell_num : 0; local_ref_flags_cell_num = local_ref_flags_cell_num > 2 ? local_ref_flags_cell_num : 2; @@ -2614,7 +2650,7 @@ aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset, func_type->types[j])) return false; } - for (; j < 2; j++) + for (j = 0; j < paddings; j++) EMIT_U8(0); } diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 8b24bcab8..24511ffd0 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -374,7 +374,9 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } #if WASM_ENABLE_DEBUG_AOT != 0 - LLVMInstructionSetDebugLoc(ret, return_location); + if (return_location != NULL) { + LLVMInstructionSetDebugLoc(ret, return_location); + } #endif } else { @@ -383,7 +385,9 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } #if WASM_ENABLE_DEBUG_AOT != 0 - LLVMInstructionSetDebugLoc(ret, return_location); + if (return_location != NULL) { + LLVMInstructionSetDebugLoc(ret, return_location); + } #endif } } @@ -1265,6 +1269,7 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, PUSH(values[j], target_block->result_types[j]); } wasm_runtime_free(values); + values = NULL; } target_block->is_reachable = true; if (i == br_count) @@ -1290,6 +1295,7 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, PUSH(values[j], target_block->param_types[j]); } wasm_runtime_free(values); + values = NULL; } if (i == br_count) default_llvm_block = target_block->llvm_entry_block; diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 224173163..cf3824e9a 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -1826,6 +1826,52 @@ fail: return ret; } +#if WASM_ENABLE_GC != 0 +static LLVMValueRef +call_aot_func_type_is_super_of_func(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, + LLVMValueRef type_idx1, + LLVMValueRef type_idx2) +{ + LLVMValueRef param_values[3], ret_value, value, func; + LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; + + param_types[0] = comp_ctx->aot_inst_type; + param_types[1] = I32_TYPE; + param_types[2] = I32_TYPE; + ret_type = INT8_TYPE; + +#if WASM_ENABLE_JIT != 0 + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_func_type_is_super_of, 3); + else +#endif + GET_AOT_FUNCTION(aot_func_type_is_super_of, 3); + + param_values[0] = func_ctx->aot_inst; + param_values[1] = type_idx1; + param_values[2] = type_idx2; + + if (!(ret_value = + LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, + 3, "call_aot_func_type_is_super_of"))) { + aot_set_last_error("llvm build call failed."); + return NULL; + } + + if (!(ret_value = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, ret_value, + I8_ZERO, "check_fail"))) { + aot_set_last_error("llvm build icmp failed."); + return NULL; + } + + return ret_value; + +fail: + return NULL; +} +#endif + static bool call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, AOTFuncType *aot_func_type, @@ -2018,15 +2064,23 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } - /* Find the equivalent function type whose type index is the smallest: - the callee function's type index is also converted to the smallest - one in wasm loader, so we can just check whether the two type indexes - are equal (the type index of call_indirect opcode and callee func), - we don't need to check whether the whole function types are equal, - including param types and result types. */ - type_idx = - wasm_get_smallest_type_idx((WASMTypePtr *)comp_ctx->comp_data->types, - comp_ctx->comp_data->type_count, type_idx); + if (!comp_ctx->enable_gc) { + /* Find the equivalent function type whose type index is the smallest: + the callee function's type index is also converted to the smallest + one in wasm loader, so we can just check whether the two type indexes + are equal (the type index of call_indirect opcode and callee func), + we don't need to check whether the whole function types are equal, + including param types and result types. */ + type_idx = wasm_get_smallest_type_idx( + (WASMTypePtr *)comp_ctx->comp_data->types, + comp_ctx->comp_data->type_count, type_idx); + } + else { + /* Call aot_func_type_is_super_of to check whether the func type + provided in the bytecode is a super type of the func type of + the function to call */ + } + ftype_idx_const = I32_CONST(type_idx); CHECK_LLVM_CONST(ftype_idx_const); @@ -2254,11 +2308,23 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - /* Check if function type index not equal */ - if (!(cmp_ftype_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, ftype_idx, - ftype_idx_const, "cmp_ftype_idx"))) { - aot_set_last_error("llvm build icmp failed."); - goto fail; +#if WASM_ENABLE_GC != 0 + if (comp_ctx->enable_gc) { + if (!(cmp_ftype_idx = call_aot_func_type_is_super_of_func( + comp_ctx, func_ctx, ftype_idx_const, ftype_idx))) { + goto fail; + } + } + else +#endif + { + /* Check if function type index not equal */ + if (!(cmp_ftype_idx = + LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, ftype_idx, + ftype_idx_const, "cmp_ftype_idx"))) { + aot_set_last_error("llvm build icmp failed."); + goto fail; + } } /* Throw exception if ftype_idx != ftype_idx_const */ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 79a39d06a..3af56e8b6 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -85,7 +85,7 @@ aot_add_llvm_func1(const AOTCompContext *comp_ctx, LLVMModuleRef module, uint32 func_index, uint32 param_count, LLVMTypeRef func_type, const char *prefix) { - char func_name[48]; + char func_name[48] = { 0 }; LLVMValueRef func; LLVMValueRef local_value; uint32 i, j; @@ -674,7 +674,8 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module, uint32 backend_thread_num, compile_thread_num; /* Check function parameter types and result types */ - for (i = 0; i < aot_func_type->param_count + aot_func_type->result_count; + for (i = 0; + i < (uint32)(aot_func_type->param_count + aot_func_type->result_count); i++) { if (!check_wasm_type(comp_ctx, aot_func_type->types[i])) return NULL; @@ -2547,6 +2548,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) aot_set_last_error("create LLVM module failed."); goto fail; } +#if LLVM_VERSION_MAJOR >= 19 + LLVMSetIsNewDbgInfoFormat(comp_ctx->module, true); +#endif #if WASM_ENABLE_LINUX_PERF != 0 if (wasm_runtime_get_linux_perf()) { diff --git a/core/iwasm/compilation/debug/dwarf_extractor.cpp b/core/iwasm/compilation/debug/dwarf_extractor.cpp index 06618ad70..e2e515ba0 100644 --- a/core/iwasm/compilation/debug/dwarf_extractor.cpp +++ b/core/iwasm/compilation/debug/dwarf_extractor.cpp @@ -295,6 +295,28 @@ lldb_function_to_function_dbi(const AOTCompContext *comp_ctx, const size_t num_function_args = function_args.GetSize(); dwarf_extractor *extractor; + /* + * Process only known languages. + * We have a few assumptions which might not be true for non-C functions. + * + * At least it's known broken for C++ and Rust: + * https://github.com/bytecodealliance/wasm-micro-runtime/issues/3187 + * https://github.com/bytecodealliance/wasm-micro-runtime/issues/3163 + */ + LanguageType language_type = function.GetLanguage(); + switch (language_type) { + case eLanguageTypeC89: + case eLanguageTypeC: + case eLanguageTypeC99: + case eLanguageTypeC11: + case eLanguageTypeC17: + break; + default: + LOG_WARNING("func %s has unsuppoted language_type 0x%x", + function_name, (int)language_type); + return NULL; + } + if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor))) return NULL; @@ -313,6 +335,17 @@ lldb_function_to_function_dbi(const AOTCompContext *comp_ctx, if (function_arg_type.IsValid()) { ParamTypes[function_arg_idx + 1] = lldb_type_to_type_dbi(comp_ctx, function_arg_type); + if (ParamTypes[function_arg_idx + 1] == NULL) { + LOG_WARNING( + "func %s arg %" PRIu32 + " has a type not implemented by lldb_type_to_type_dbi", + function_name, function_arg_idx); + } + } + else { + LOG_WARNING("func %s arg %" PRIu32 ": GetTypeAtIndex failed", + function_name, function_arg_idx); + ParamTypes[function_arg_idx + 1] = NULL; } } @@ -354,27 +387,10 @@ lldb_function_to_function_dbi(const AOTCompContext *comp_ctx, LLVMDIBuilderCreateExpression(DIB, NULL, 0); auto variable_list = function.GetBlock().GetVariables(extractor->target, true, false, false); - unsigned int variable_offset = 0; if (num_function_args != variable_list.GetSize()) { - // A hack to detect C++ "this" pointer. - // - // REVISIT: is there a more reliable way? - // At the DWARF level, we can probably look at DW_AT_object_pointer - // and DW_AT_artificial. I'm not sure how it can be done via the - // LLDB API though. - if (num_function_args + 1 == variable_list.GetSize()) { - SBValue variable(variable_list.GetValueAtIndex(0)); - const char *varname = variable.GetName(); - if (varname != NULL && !strcmp(varname, "this")) { - variable_offset = 1; - } - } - if (!variable_offset) { - LOG_ERROR("function args number dismatch!:function %s %s value " - "number=%d, function args=%d", - function_name, function.GetMangledName(), - variable_list.GetSize(), num_function_args); - } + LOG_ERROR( + "function args number dismatch!:value number=%d, function args=%d", + variable_list.GetSize(), num_function_args); } LLVMMetadataRef ParamLocation = LLVMDIBuilderCreateDebugLocation( @@ -395,11 +411,10 @@ lldb_function_to_function_dbi(const AOTCompContext *comp_ctx, LLVMDIBuilderInsertDbgValueAtEnd(DIB, Param, ParamVar, ParamExpression, ParamLocation, block_curr); - for (uint32_t function_arg_idx = 0; function_arg_idx < num_function_args; - ++function_arg_idx) { - uint32_t variable_idx = variable_offset + function_arg_idx; - SBValue variable(variable_list.GetValueAtIndex(variable_idx)); - if (variable.IsValid()) { + for (uint32_t function_arg_idx = 0; + function_arg_idx < variable_list.GetSize(); ++function_arg_idx) { + SBValue variable(variable_list.GetValueAtIndex(function_arg_idx)); + if (variable.IsValid() && ParamTypes[function_arg_idx + 1] != NULL) { SBDeclaration dec(variable.GetDeclaration()); auto valtype = variable.GetType(); LLVMMetadataRef ParamLocation = LLVMDIBuilderCreateDebugLocation( @@ -408,11 +423,12 @@ lldb_function_to_function_dbi(const AOTCompContext *comp_ctx, const char *varname = variable.GetName(); LLVMMetadataRef ParamVar = LLVMDIBuilderCreateParameterVariable( DIB, FunctionMetadata, varname, varname ? strlen(varname) : 0, - variable_idx + 1 + 1, + function_arg_idx + 1 + 1, File, // starts form 1, and 1 is exenv, dec.GetLine(), ParamTypes[function_arg_idx + 1], true, LLVMDIFlagZero); - LLVMValueRef Param = LLVMGetParam(func_ctx->func, variable_idx + 1); + LLVMValueRef Param = + LLVMGetParam(func_ctx->func, function_arg_idx + 1); LLVMDIBuilderInsertDbgValueAtEnd(DIB, Param, ParamVar, ParamExpression, ParamLocation, block_curr); @@ -491,6 +507,8 @@ dwarf_gen_location(const AOTCompContext *comp_ctx, dwarf_extractor *extractor; AOTFunc *func = func_ctx->aot_func; + if (func_ctx->debug_func == NULL) + return NULL; if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor))) return NULL; diff --git a/core/iwasm/compilation/simd/simd_conversions.c b/core/iwasm/compilation/simd/simd_conversions.c index 8e4c17ed3..042e28089 100644 --- a/core/iwasm/compilation/simd/simd_conversions.c +++ b/core/iwasm/compilation/simd/simd_conversions.c @@ -226,15 +226,6 @@ aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, } } -bool -aot_compile_simd_i32x4_narrow_i64x2(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx, bool is_signed) -{ - /* TODO: x86 intrinsics */ - return simd_integer_narrow_common(comp_ctx, func_ctx, e_sat_i64x2, - is_signed); -} - enum integer_extend_type { e_ext_i8x16, e_ext_i16x8, diff --git a/core/iwasm/compilation/simd/simd_conversions.h b/core/iwasm/compilation/simd/simd_conversions.h index 87b8bd684..e3a1a3521 100644 --- a/core/iwasm/compilation/simd/simd_conversions.h +++ b/core/iwasm/compilation/simd/simd_conversions.h @@ -20,10 +20,6 @@ bool aot_compile_simd_i16x8_narrow_i32x4(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool is_signed); -bool -aot_compile_simd_i32x4_narrow_i64x2(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx, bool is_signed); - bool aot_compile_simd_i16x8_extend_i8x16(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool is_low, diff --git a/core/iwasm/compilation/simd/simd_floating_point.c b/core/iwasm/compilation/simd/simd_floating_point.c index 7fcc1ab65..536ef5b28 100644 --- a/core/iwasm/compilation/simd/simd_floating_point.c +++ b/core/iwasm/compilation/simd/simd_floating_point.c @@ -129,20 +129,6 @@ aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) "llvm.fabs.v2f64"); } -bool -aot_compile_simd_f32x4_round(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) -{ - return simd_float_intrinsic(comp_ctx, func_ctx, V128_f32x4_TYPE, - "llvm.round.v4f32"); -} - -bool -aot_compile_simd_f64x2_round(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) -{ - return simd_float_intrinsic(comp_ctx, func_ctx, V128_f64x2_TYPE, - "llvm.round.v2f64"); -} - bool aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { diff --git a/core/iwasm/compilation/simd/simd_floating_point.h b/core/iwasm/compilation/simd/simd_floating_point.h index 213b4391f..39e37c872 100644 --- a/core/iwasm/compilation/simd/simd_floating_point.h +++ b/core/iwasm/compilation/simd/simd_floating_point.h @@ -32,14 +32,6 @@ aot_compile_simd_f32x4_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); bool aot_compile_simd_f64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); -bool -aot_compile_simd_f32x4_round(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx); - -bool -aot_compile_simd_f64x2_round(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx); - bool aot_compile_simd_f32x4_sqrt(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); diff --git a/core/iwasm/compilation/simd/simd_int_arith.c b/core/iwasm/compilation/simd/simd_int_arith.c index 1d0e6967b..6a1902d1f 100644 --- a/core/iwasm/compilation/simd/simd_int_arith.c +++ b/core/iwasm/compilation/simd/simd_int_arith.c @@ -243,7 +243,6 @@ aot_compile_simd_i64x2_abs(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) enum integer_avgr_u { e_avgr_u_i8x16, e_avgr_u_i16x8, - e_avgr_u_i32x4, }; /* TODO: try int_x86_mmx_pavg_b and int_x86_mmx_pavg_w */ @@ -257,9 +256,8 @@ simd_v128_avg(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMTypeRef vector_type[] = { V128_i8x16_TYPE, V128_i16x8_TYPE, - V128_i32x4_TYPE, }; - unsigned lanes[] = { 16, 8, 4 }; + unsigned lanes[] = { 16, 8 }; if (!(rhs = simd_pop_v128_and_bitcast(comp_ctx, func_ctx, vector_type[itype], "rhs")) @@ -325,13 +323,6 @@ aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx, return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i16x8); } -bool -aot_compile_simd_i32x4_avgr_u(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx) -{ - return simd_v128_avg(comp_ctx, func_ctx, e_avgr_u_i32x4); -} - bool aot_compile_simd_i32x4_dot_i16x8(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) diff --git a/core/iwasm/compilation/simd/simd_int_arith.h b/core/iwasm/compilation/simd/simd_int_arith.h index a7a21170a..49827d51d 100644 --- a/core/iwasm/compilation/simd/simd_int_arith.h +++ b/core/iwasm/compilation/simd/simd_int_arith.h @@ -76,10 +76,6 @@ bool aot_compile_simd_i16x8_avgr_u(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); -bool -aot_compile_simd_i32x4_avgr_u(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx); - bool aot_compile_simd_i32x4_dot_i16x8(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); diff --git a/core/iwasm/compilation/simd/simd_sat_int_arith.c b/core/iwasm/compilation/simd/simd_sat_int_arith.c index 1de4520a7..ea250b7e0 100644 --- a/core/iwasm/compilation/simd/simd_sat_int_arith.c +++ b/core/iwasm/compilation/simd/simd_sat_int_arith.c @@ -64,18 +64,3 @@ aot_compile_simd_i16x8_saturate(AOTCompContext *comp_ctx, is_signed ? intrinsics[arith_op][0] : intrinsics[arith_op][1]); } - -bool -aot_compile_simd_i32x4_saturate(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx, - V128Arithmetic arith_op, bool is_signed) -{ - char *intrinsics[][2] = { - { "llvm.sadd.sat.v4i32", "llvm.uadd.sat.v4i32" }, - { "llvm.ssub.sat.v4i32", "llvm.usub.sat.v4i32" }, - }; - - return simd_sat_int_arith(comp_ctx, func_ctx, V128_i16x8_TYPE, - is_signed ? intrinsics[arith_op][0] - : intrinsics[arith_op][1]); -} diff --git a/core/iwasm/compilation/simd/simd_sat_int_arith.h b/core/iwasm/compilation/simd/simd_sat_int_arith.h index e30acaaf4..67c602fc5 100644 --- a/core/iwasm/compilation/simd/simd_sat_int_arith.h +++ b/core/iwasm/compilation/simd/simd_sat_int_arith.h @@ -22,10 +22,6 @@ aot_compile_simd_i16x8_saturate(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, V128Arithmetic arith_op, bool is_signed); -bool -aot_compile_simd_i32x4_saturate(AOTCompContext *comp_ctx, - AOTFuncContext *func_ctx, - V128Arithmetic arith_op, bool is_signed); #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp b/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp index f5605b6f2..79c72503e 100644 --- a/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp +++ b/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp @@ -7511,7 +7511,7 @@ at_rmw_xor_r_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, CHECK_KIND(r3, JIT_REG_KIND_I64); \ } \ /* r0: read/return value r2: memory base addr can't be const */ \ - /* already check it's not const in LOAD_4ARGS(); */ \ + /* already check it's not const in LOAD_4ARGS() */ \ reg_no_dst = jit_reg_no(r0); \ CHECK_REG_NO(reg_no_dst, jit_reg_kind(r0)); \ /* mem_data base address has to be non-const */ \ @@ -9293,8 +9293,8 @@ jit_codegen_init() imm.setValue(INT32_MAX); a.jne(imm); - char *stream = (char *)a.code()->sectionById(0)->buffer().data() - + a.code()->sectionById(0)->buffer().size(); + char *stream_old = (char *)a.code()->sectionById(0)->buffer().data() + + a.code()->sectionById(0)->buffer().size(); /* If yes, call jit_set_exception_with_id to throw exception, and then set eax to JIT_INTERP_ACTION_THROWN, and jump to @@ -9319,7 +9319,7 @@ jit_codegen_init() /* Patch the offset of jne instruction */ char *stream_new = (char *)a.code()->sectionById(0)->buffer().data() + a.code()->sectionById(0)->buffer().size(); - *(int32 *)(stream - 4) = (int32)(stream_new - stream); + *(int32 *)(stream_old - 4) = (int32)(stream_new - stream_old); } /* Load compiled func ptr and call it */ @@ -9419,7 +9419,7 @@ static uint8 hreg_info_F64[3][16] = { 1, 1, 1, 1, 1, 1, 1, 0 }, /* caller_saved_jitted */ }; -static const JitHardRegInfo hreg_info = { +static const JitHardRegInfo g_hreg_info = { { { 0, NULL, NULL, NULL }, /* VOID */ @@ -9459,7 +9459,7 @@ static const JitHardRegInfo hreg_info = { const JitHardRegInfo * jit_codegen_get_hreg_info() { - return &hreg_info; + return &g_hreg_info; } static const char *reg_names_i32[] = { diff --git a/core/iwasm/fast-jit/fe/jit_emit_memory.c b/core/iwasm/fast-jit/fe/jit_emit_memory.c index 0a977c1d6..ea245ba34 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_memory.c +++ b/core/iwasm/fast-jit/fe/jit_emit_memory.c @@ -636,7 +636,7 @@ wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx, /* if d + n > the length of mem.data */ mem_inst = inst->memories[mem_idx]; - mem_size = mem_inst->cur_page_count * mem_inst->num_bytes_per_page; + mem_size = mem_inst->cur_page_count * (uint64)mem_inst->num_bytes_per_page; if (mem_size < mem_offset || mem_size - mem_offset < len) goto out_of_bounds; @@ -724,8 +724,10 @@ wasm_copy_memory(WASMModuleInstance *inst, uint32 src_mem_idx, src_mem = inst->memories[src_mem_idx]; dst_mem = inst->memories[dst_mem_idx]; - src_mem_size = src_mem->cur_page_count * src_mem->num_bytes_per_page; - dst_mem_size = dst_mem->cur_page_count * dst_mem->num_bytes_per_page; + src_mem_size = + src_mem->cur_page_count * (uint64)src_mem->num_bytes_per_page; + dst_mem_size = + dst_mem->cur_page_count * (uint64)dst_mem->num_bytes_per_page; /* if s + n > the length of mem.data */ if (src_mem_size < src_offset || src_mem_size - src_offset < len) @@ -788,7 +790,7 @@ wasm_fill_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 len, uint8 *dst_addr; mem_inst = inst->memories[mem_idx]; - mem_size = mem_inst->cur_page_count * mem_inst->num_bytes_per_page; + mem_size = mem_inst->cur_page_count * (uint64)mem_inst->num_bytes_per_page; if (mem_size < dst || mem_size - dst < len) goto out_of_bounds; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index c1a03d86c..d06fef1dd 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -3,6 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/** + * @file aot_export.h + * + * @brief This file defines the exported AOT compilation APIs + */ + #ifndef _AOT_EXPORT_H #define _AOT_EXPORT_H diff --git a/core/iwasm/include/gc_export.h b/core/iwasm/include/gc_export.h index 3eb88dbab..777551edc 100644 --- a/core/iwasm/include/gc_export.h +++ b/core/iwasm/include/gc_export.h @@ -3,6 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/** + * @file gc_export.h + * + * @brief This file defines the exported GC APIs + */ + #ifndef _GC_EXPORT_H #define _GC_EXPORT_H diff --git a/core/iwasm/include/lib_export.h b/core/iwasm/include/lib_export.h index e4829e4fe..0ca668f52 100644 --- a/core/iwasm/include/lib_export.h +++ b/core/iwasm/include/lib_export.h @@ -3,6 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/** + * @file lib_export.h + * + */ + #ifndef _LIB_EXPORT_H_ #define _LIB_EXPORT_H_ diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index 606b9ff82..63d18f3ae 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -1,5 +1,11 @@ // WebAssembly C API +/** + * @file wasm_c_api.h + * + * @brief This file defines the WebAssembly C APIs + */ + #ifndef _WASM_C_API_H_ #define _WASM_C_API_H_ @@ -517,10 +523,21 @@ struct WASMModuleCommon; typedef struct WASMModuleCommon *wasm_module_t; #endif +#ifndef LOAD_ARGS_OPTION_DEFINED +#define LOAD_ARGS_OPTION_DEFINED +typedef struct LoadArgs { + char *name; + /* TODO: more fields? */ +} LoadArgs; +#endif /* LOAD_ARGS_OPTION_DEFINED */ WASM_API_EXTERN own wasm_module_t* wasm_module_new( wasm_store_t*, const wasm_byte_vec_t* binary); +// please refer to wasm_runtime_load_ex(...) in core/iwasm/include/wasm_export.h +WASM_API_EXTERN own wasm_module_t* wasm_module_new_ex( + wasm_store_t*, const wasm_byte_vec_t* binary, const LoadArgs *args); + WASM_API_EXTERN void wasm_module_delete(own wasm_module_t*); WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index b40a3440a..7cd266e12 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -3,6 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/** + * @file wasm_export.h + * + * @brief This file defines the exported common runtime APIs + */ + #ifndef _WASM_EXPORT_H #define _WASM_EXPORT_H @@ -107,6 +113,11 @@ typedef enum { Alloc_With_System_Allocator, } mem_alloc_type_t; +typedef enum { + Alloc_For_Runtime, + Alloc_For_LinearMemory +} mem_alloc_usage_t; + /* Memory allocator option */ typedef union MemAllocOption { struct { @@ -114,6 +125,9 @@ typedef union MemAllocOption { uint32_t heap_size; } pool; struct { + /* the function signature is varied when + WASM_MEM_ALLOC_WITH_USER_DATA and + WASM_MEM_ALLOC_WITH_USAGE are defined */ void *malloc_func; void *realloc_func; void *free_func; @@ -183,6 +197,14 @@ typedef struct RuntimeInitArgs { bool enable_linux_perf; } RuntimeInitArgs; +#ifndef LOAD_ARGS_OPTION_DEFINED +#define LOAD_ARGS_OPTION_DEFINED +typedef struct LoadArgs { + char *name; + /* TODO: more fields? */ +} LoadArgs; +#endif /* LOAD_ARGS_OPTION_DEFINED */ + #ifndef INSTANTIATION_ARGS_OPTION_DEFINED #define INSTANTIATION_ARGS_OPTION_DEFINED /* WASM module instantiation arguments */ @@ -419,6 +441,13 @@ WASM_RUNTIME_API_EXTERN wasm_module_t wasm_runtime_load(uint8_t *buf, uint32_t size, char *error_buf, uint32_t error_buf_size); +/** + * Load a WASM module with specified load argument. + */ +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); + /** * Load a WASM module from a specified WASM or AOT section list. * diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 56c8ebe75..5c436cbfa 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -90,11 +90,22 @@ extern "C" { */ #define VALUE_TYPE_GC_REF 0x43 +#define MAX_PAGE_COUNT_FLAG 0x01 +#define SHARED_MEMORY_FLAG 0x02 +#define MEMORY64_FLAG 0x04 + #define DEFAULT_NUM_BYTES_PER_PAGE 65536 #define DEFAULT_MAX_PAGES 65536 +#define DEFAULT_MEM64_MAX_PAGES UINT32_MAX /* Max size of linear memory */ #define MAX_LINEAR_MEMORY_SIZE (4 * (uint64)BH_GB) +/* Roughly 274 TB */ +#define MAX_LINEAR_MEM64_MEMORY_SIZE \ + (DEFAULT_MEM64_MAX_PAGES * (uint64)64 * (uint64)BH_KB) +/* Macro to check memory flag and return appropriate memory size */ +#define GET_MAX_LINEAR_MEMORY_SIZE(is_memory64) \ + (is_memory64 ? MAX_LINEAR_MEM64_MEMORY_SIZE : MAX_LINEAR_MEMORY_SIZE) #if WASM_ENABLE_GC == 0 typedef uintptr_t table_elem_type_t; @@ -263,7 +274,7 @@ typedef struct InitializerExpression { */ typedef struct RefHeapType_TypeIdx { /* ref_type is REF_TYPE_HT_NULLABLE or - REF_TYPE_HT_NON_NULLABLE, (0x6C or 0x6B) */ + REF_TYPE_HT_NON_NULLABLE, (0x63 or 0x64) */ uint8 ref_type; /* true if ref_type is REF_TYPE_HT_NULLABLE */ bool nullable; @@ -277,7 +288,7 @@ typedef struct RefHeapType_TypeIdx { */ typedef struct RefHeapType_Common { /* ref_type is REF_TYPE_HT_NULLABLE or - REF_TYPE_HT_NON_NULLABLE (0x6C or 0x6B) */ + REF_TYPE_HT_NON_NULLABLE (0x63 or 0x64) */ uint8 ref_type; /* true if ref_type is REF_TYPE_HT_NULLABLE */ bool nullable; @@ -327,18 +338,24 @@ typedef struct WASMType { uint16 type_flag; bool is_sub_final; + /* How many types are referring to this type */ + uint16 ref_count; /* The inheritance depth */ - uint32 inherit_depth; + uint16 inherit_depth; /* The root type */ struct WASMType *root_type; /* The parent type */ struct WASMType *parent_type; uint32 parent_type_idx; - /* number of internal types in the current rec group, if the type is not in - * a recursive group, rec_count = 0 */ + /* The number of internal types in the current rec group, and if + the type is not in a recursive group, rec_count is 1 since a + single type definition is reinterpreted as a short-hand for a + recursive group containing just one type */ uint16 rec_count; uint16 rec_idx; + /* The index of the begin type of this group */ + uint32 rec_begin_type_idx; } WASMType, *WASMTypePtr; #endif /* end of WASM_ENABLE_GC */ @@ -364,9 +381,6 @@ typedef struct WASMFuncType { uint16 ref_type_map_count; WASMRefTypeMap *ref_type_maps; WASMRefTypeMap *result_ref_type_maps; - /* minimal type index of the type equal to this type, - used in type equal check in call_indirect opcode */ - uint32 min_type_idx_normalized; #else uint16 ref_count; #endif @@ -484,6 +498,12 @@ typedef struct WASMTable { #endif } WASMTable; +#if WASM_ENABLE_MEMORY64 != 0 +typedef uint64 mem_offset_t; +#else +typedef uint32 mem_offset_t; +#endif + typedef struct WASMMemory { uint32 flags; uint32 num_bytes_per_page; @@ -1312,8 +1332,8 @@ block_type_get_param_types(BlockType *block_type, uint8 **p_param_types, param_count = func_type->param_count; #if WASM_ENABLE_GC != 0 *p_param_reftype_maps = func_type->ref_type_maps; - *p_param_reftype_map_count = - func_type->result_ref_type_maps - func_type->ref_type_maps; + *p_param_reftype_map_count = (uint32)(func_type->result_ref_type_maps + - func_type->ref_type_maps); #endif } else { diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index d8fd2d708..89e6ac57b 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -46,8 +46,10 @@ typedef float64 CellType_F64; #define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory) #endif -#if !defined(OS_ENABLE_HW_BOUND_CHECK) \ - || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 +#if WASM_ENABLE_MEMORY64 == 0 + +#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; \ @@ -69,7 +71,8 @@ typedef float64 CellType_F64; else \ goto out_of_bounds; \ } while (0) -#else +#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; \ @@ -80,8 +83,37 @@ typedef float64 CellType_F64; do { \ maddr = memory->memory_data + (uint32)(start); \ } while (0) -#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \ - || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ +#endif /* end of !defined(OS_ENABLE_HW_BOUND_CHECK) || \ + WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ + +#else /* else of WASM_ENABLE_MEMORY64 == 0 */ + +#define CHECK_MEMORY_OVERFLOW(bytes) \ + do { \ + uint64 offset1 = (uint64)offset + (uint64)addr; \ + /* If memory64 is enabled, offset1, offset1 + bytes can overflow */ \ + if (disable_bounds_checks \ + || (offset1 >= offset && offset1 + bytes >= offset1 \ + && offset1 + bytes <= get_linear_mem_size())) \ + maddr = memory->memory_data + offset1; \ + else \ + goto out_of_bounds; \ + } while (0) +#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ + do { \ + uint64 offset1 = (uint64)(start); \ + /* If memory64 is enabled, offset1 + bytes can overflow */ \ + if (disable_bounds_checks \ + || (offset1 + bytes >= offset1 \ + && offset1 + bytes <= get_linear_mem_size())) \ + /* App heap space is not valid space for \ + bulk memory operation */ \ + maddr = memory->memory_data + offset1; \ + else \ + goto out_of_bounds; \ + } while (0) + +#endif /* end of WASM_ENABLE_MEMORY64 == 0 */ #define CHECK_ATOMIC_MEMORY_ACCESS() \ do { \ @@ -472,6 +504,23 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) #define SET_LABEL_TYPE(_label_type) (void)0 #endif +#if WASM_ENABLE_MEMORY64 != 0 +#define PUSH_MEM_OFFSET(value) \ + do { \ + if (is_memory64) { \ + PUT_I64_TO_ADDR(frame_sp, value); \ + frame_sp += 2; \ + } \ + else { \ + *(int32 *)frame_sp++ = (int32)(value); \ + } \ + } while (0) +#else +#define PUSH_MEM_OFFSET(value) PUSH_I32(value) +#endif + +#define PUSH_PAGE_COUNT(value) PUSH_MEM_OFFSET(value) + #define PUSH_CSP(_label_type, param_cell_num, cell_num, _target_addr) \ do { \ bh_assert(frame_csp < frame->csp_boundary); \ @@ -501,6 +550,14 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) GET_REF_FROM_ADDR(frame_sp)) #endif +#if WASM_ENABLE_MEMORY64 != 0 +#define POP_MEM_OFFSET() (is_memory64 ? POP_I64() : POP_I32()) +#else +#define POP_MEM_OFFSET() POP_I32() +#endif + +#define POP_PAGE_COUNT() POP_MEM_OFFSET() + #define POP_CSP_CHECK_OVERFLOW(n) \ do { \ bh_assert(frame_csp - n >= frame->csp_bottom); \ @@ -567,51 +624,73 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) frame_csp = frame->csp; \ } while (0) -#define read_leb_int64(p, p_end, res) \ - do { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = (int64)_val; \ - if (_val & 0x40) \ - /* sign extend */ \ - res |= 0xFFFFFFFFFFFFFF80LL; \ - p++; \ - break; \ - } \ - uint32 _off = 0; \ - res = (int64)read_leb(p, &_off, 64, true); \ - p += _off; \ +#define read_leb_int64(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = (int64)_val; \ + if (_val & 0x40) \ + /* sign extend */ \ + res |= 0xFFFFFFFFFFFFFF80LL; \ + p++; \ + } \ + else { \ + uint32 _off = 0; \ + res = (int64)read_leb(p, &_off, 64, true); \ + p += _off; \ + } \ } while (0) -#define read_leb_uint32(p, p_end, res) \ - do { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = _val; \ - p++; \ - break; \ - } \ - uint32 _off = 0; \ - res = (uint32)read_leb(p, &_off, 32, false); \ - p += _off; \ +#define read_leb_uint32(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = _val; \ + p++; \ + } \ + else { \ + uint32 _off = 0; \ + res = (uint32)read_leb(p, &_off, 32, false); \ + p += _off; \ + } \ } while (0) -#define read_leb_int32(p, p_end, res) \ - do { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = (int32)_val; \ - if (_val & 0x40) \ - /* sign extend */ \ - res |= 0xFFFFFF80; \ - p++; \ - break; \ - } \ - uint32 _off = 0; \ - res = (int32)read_leb(p, &_off, 32, true); \ - p += _off; \ +#define read_leb_int32(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = (int32)_val; \ + if (_val & 0x40) \ + /* sign extend */ \ + res |= 0xFFFFFF80; \ + p++; \ + } \ + else { \ + uint32 _off = 0; \ + res = (int32)read_leb(p, &_off, 32, true); \ + p += _off; \ + } \ } while (0) +#if WASM_ENABLE_MEMORY64 != 0 +#define read_leb_mem_offset(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = (mem_offset_t)_val; \ + p++; \ + } \ + else { \ + uint32 _off = 0; \ + res = (mem_offset_t)read_leb(p, &_off, is_memory64 ? 64 : 32, \ + false); \ + p += _off; \ + } \ + } while (0) +#else +#define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res) +#endif + #if WASM_ENABLE_LABELS_AS_VALUES == 0 #define RECOVER_FRAME_IP_END() frame_ip_end = wasm_get_func_code_end(cur_func) #else @@ -872,7 +951,7 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, uint32 readv, sval; \ \ sval = POP_I32(); \ - addr = POP_I32(); \ + addr = POP_MEM_OFFSET(); \ \ if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U) { \ CHECK_MEMORY_OVERFLOW(1); \ @@ -912,7 +991,7 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, uint64 readv, sval; \ \ sval = (uint64)POP_I64(); \ - addr = POP_I32(); \ + addr = POP_MEM_OFFSET(); \ \ if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U) { \ CHECK_MEMORY_OVERFLOW(1); \ @@ -1430,6 +1509,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMStringviewIterObjectRef stringview_iter_obj; #endif #endif +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + bool is_return_call = false; +#endif +#if WASM_ENABLE_MEMORY64 != 0 + /* TODO: multi-memories for now assuming the memory idx type is consistent + * across multi-memories */ + bool is_memory64 = false; + if (memory) + is_memory64 = memory->is_memory64; +#endif #if WASM_ENABLE_DEBUG_INTERP != 0 uint8 *frame_ip_orig = NULL; @@ -2123,6 +2212,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMFuncType *cur_type, *cur_func_type; WASMTableInstance *tbl_inst; uint32 tbl_idx; + #if WASM_ENABLE_TAIL_CALL != 0 opcode = *(frame_ip - 1); #endif @@ -2193,8 +2283,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } #else - if (cur_type->min_type_idx_normalized - != cur_func_type->min_type_idx_normalized) { + if (!wasm_func_type_is_super_of(cur_type, cur_func_type)) { wasm_set_exception(module, "indirect call type mismatch"); goto got_exception; } @@ -4087,8 +4176,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); - /* TODO: Memory64 the data type depends on mem idx type */ - aux_stack_top = (uint64)(*(uint32 *)(frame_sp - 1)); +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + aux_stack_top = *(uint64 *)(frame_sp - 2); + } + else +#endif + { + aux_stack_top = (uint64)(*(uint32 *)(frame_sp - 1)); + } if (aux_stack_top <= (uint64)exec_env->aux_stack_boundary) { wasm_set_exception(module, "wasm auxiliary stack overflow"); goto got_exception; @@ -4098,8 +4194,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, "wasm auxiliary stack underflow"); goto got_exception; } - *(int32 *)global_addr = aux_stack_top; - frame_sp--; +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + *(uint64 *)global_addr = aux_stack_top; + frame_sp -= 2; + } + else +#endif + { + *(uint32 *)global_addr = aux_stack_top; + frame_sp--; + } #if WASM_ENABLE_MEMORY_PROFILING != 0 if (module->module->aux_stack_top_global_index != (uint32)-1) { uint32 aux_stack_used = @@ -4126,11 +4231,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD) HANDLE_OP(WASM_OP_F32_LOAD) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); PUSH_I32(LOAD_I32(maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4141,11 +4247,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD) HANDLE_OP(WASM_OP_F64_LOAD) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(8); PUSH_I64(LOAD_I64(maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4155,11 +4262,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD8_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(1); PUSH_I32(sign_ext_8_32(*(int8 *)maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4169,11 +4277,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD8_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(1); PUSH_I32((uint32)(*(uint8 *)maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4183,11 +4292,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD16_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(2); PUSH_I32(sign_ext_16_32(LOAD_I16(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4197,11 +4307,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD16_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(2); PUSH_I32((uint32)(LOAD_U16(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4211,11 +4322,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD8_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(1); PUSH_I64(sign_ext_8_64(*(int8 *)maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4225,11 +4337,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD8_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(1); PUSH_I64((uint64)(*(uint8 *)maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4239,11 +4352,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD16_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(2); PUSH_I64(sign_ext_16_64(LOAD_I16(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4253,11 +4367,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD16_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(2); PUSH_I64((uint64)(LOAD_U16(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4267,12 +4382,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD32_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); PUSH_I64(sign_ext_32_64(LOAD_I32(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4282,11 +4398,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD32_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); PUSH_I64((uint64)(LOAD_U32(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4298,14 +4415,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_STORE) HANDLE_OP(WASM_OP_F32_STORE) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); frame_sp--; - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); - STORE_U32(maddr, frame_sp[1]); +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + STORE_U32(maddr, frame_sp[2]); + } + else +#endif + { + STORE_U32(maddr, frame_sp[1]); + } CHECK_WRITE_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); @@ -4314,15 +4440,26 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_STORE) HANDLE_OP(WASM_OP_F64_STORE) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); frame_sp -= 2; - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(8); - PUT_I64_TO_ADDR((uint32 *)maddr, - GET_I64_FROM_ADDR(frame_sp + 1)); + +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + PUT_I64_TO_ADDR((mem_offset_t *)maddr, + GET_I64_FROM_ADDR(frame_sp + 2)); + } + else +#endif + { + PUT_I64_TO_ADDR((uint32 *)maddr, + GET_I64_FROM_ADDR(frame_sp + 1)); + } CHECK_WRITE_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); @@ -4331,14 +4468,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_STORE8) HANDLE_OP(WASM_OP_I32_STORE16) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; uint32 sval; opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); sval = (uint32)POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_I32_STORE8) { CHECK_MEMORY_OVERFLOW(1); @@ -4357,14 +4495,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_STORE16) HANDLE_OP(WASM_OP_I64_STORE32) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; uint64 sval; opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); sval = (uint64)POP_I64(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_I64_STORE8) { CHECK_MEMORY_OVERFLOW(1); @@ -4388,7 +4527,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 reserved; read_leb_uint32(frame_ip, frame_ip_end, reserved); - PUSH_I32(memory->cur_page_count); + PUSH_PAGE_COUNT(memory->cur_page_count); (void)reserved; HANDLE_OP_END(); } @@ -4399,15 +4538,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, prev_page_count = memory->cur_page_count; read_leb_uint32(frame_ip, frame_ip_end, reserved); - delta = (uint32)POP_I32(); + delta = (uint32)POP_PAGE_COUNT(); if (!wasm_enlarge_memory(module, delta)) { /* failed to memory.grow, return -1 */ - PUSH_I32(-1); + PUSH_PAGE_COUNT(-1); } else { /* success, return previous page count */ - PUSH_I32(prev_page_count); + PUSH_PAGE_COUNT(prev_page_count); /* update memory size, no need to update memory ptr as it isn't changed in wasm_enlarge_memory */ #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ @@ -5407,7 +5546,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_BULK_MEMORY != 0 case WASM_OP_MEMORY_INIT: { - uint32 addr, segment; + uint32 segment; + mem_offset_t addr; uint64 bytes, offset, seg_len; uint8 *data; @@ -5417,7 +5557,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bytes = (uint64)(uint32)POP_I32(); offset = (uint64)(uint32)POP_I32(); - addr = (uint32)POP_I32(); + addr = (mem_offset_t)POP_MEM_OFFSET(); #if WASM_ENABLE_THREAD_MGR != 0 linear_mem_size = get_linear_mem_size(); @@ -5460,14 +5600,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } case WASM_OP_MEMORY_COPY: { - uint32 dst, src, len; + mem_offset_t dst, src, len; uint8 *mdst, *msrc; frame_ip += 2; - - len = POP_I32(); - src = POP_I32(); - dst = POP_I32(); + len = POP_MEM_OFFSET(); + src = POP_MEM_OFFSET(); + dst = POP_MEM_OFFSET(); #if WASM_ENABLE_THREAD_MGR != 0 linear_mem_size = get_linear_mem_size(); @@ -5493,13 +5632,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } case WASM_OP_MEMORY_FILL: { - uint32 dst, len; + mem_offset_t dst, len; uint8 fill_val, *mdst; frame_ip++; - len = POP_I32(); + len = POP_MEM_OFFSET(); fill_val = POP_I32(); - dst = POP_I32(); + dst = POP_MEM_OFFSET(); #if WASM_ENABLE_THREAD_MGR != 0 linear_mem_size = get_linear_mem_size(); @@ -5729,7 +5868,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_SHARED_MEMORY != 0 HANDLE_OP(WASM_OP_ATOMIC_PREFIX) { - uint32 offset = 0, align = 0, addr; + mem_offset_t offset = 0, addr; + uint32 align = 0; uint32 opcode1; read_leb_uint32(frame_ip, frame_ip_end, opcode1); @@ -5739,7 +5879,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode != WASM_OP_ATOMIC_FENCE) { read_leb_uint32(frame_ip, frame_ip_end, align); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); } switch (opcode) { @@ -5748,7 +5888,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 notify_count, ret; notify_count = POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); CHECK_ATOMIC_MEMORY_ACCESS(); @@ -5768,7 +5908,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, timeout = POP_I64(); expect = POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); CHECK_ATOMIC_MEMORY_ACCESS(); @@ -5792,7 +5932,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, timeout = POP_I64(); expect = POP_I64(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(8); CHECK_ATOMIC_MEMORY_ACCESS(); @@ -5823,7 +5963,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 readv; - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) { CHECK_MEMORY_OVERFLOW(1); @@ -5858,7 +5998,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint64 readv; - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) { CHECK_MEMORY_OVERFLOW(1); @@ -5900,7 +6040,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 sval; sval = (uint32)POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_I32_STORE8) { CHECK_MEMORY_OVERFLOW(1); @@ -5934,7 +6074,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint64 sval; sval = (uint64)POP_I64(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_I64_STORE8) { CHECK_MEMORY_OVERFLOW(1); @@ -5961,7 +6101,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_MEMORY_OVERFLOW(8); CHECK_ATOMIC_MEMORY_ACCESS(); shared_memory_lock(memory); - PUT_I64_TO_ADDR((uint32 *)maddr, sval); + STORE_I64(maddr, sval); shared_memory_unlock(memory); } break; @@ -5975,7 +6115,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, sval = POP_I32(); expect = POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U) { CHECK_MEMORY_OVERFLOW(1); @@ -6021,7 +6161,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, sval = (uint64)POP_I64(); expect = (uint64)POP_I64(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U) { CHECK_MEMORY_OVERFLOW(1); @@ -6090,6 +6230,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, frame_ip = frame->ip; frame_sp = frame->sp; frame_csp = frame->csp; +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + is_return_call = false; +#endif goto call_func_from_entry; } @@ -6183,6 +6326,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } FREE_FRAME(exec_env, frame); wasm_exec_env_set_cur_frame(exec_env, prev_frame); + is_return_call = true; goto call_func_from_entry; } #endif @@ -6196,6 +6340,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } SYNC_ALL_TO_FRAME(); prev_frame = frame; +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + is_return_call = false; +#endif } call_func_from_entry: @@ -6205,15 +6352,27 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (cur_func->import_func_inst) { wasm_interp_call_func_import(module, exec_env, cur_func, prev_frame); +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + if (is_return_call) { + /* the frame was freed before tail calling and + the prev_frame was set as exec_env's cur_frame, + so here we recover context from prev_frame */ + RECOVER_CONTEXT(prev_frame); + } + else +#endif + { + prev_frame = frame->prev_frame; + cur_func = frame->function; + UPDATE_ALL_FROM_FRAME(); + } + #if WASM_ENABLE_EXCE_HANDLING != 0 char uncaught_exception[128] = { 0 }; bool has_exception = wasm_copy_exception(module, uncaught_exception); if (has_exception && strstr(uncaught_exception, "uncaught wasm exception")) { - /* fix framesp */ - UPDATE_ALL_FROM_FRAME(); - uint32 import_exception; /* initialize imported exception index to be invalid */ SET_INVALID_TAGINDEX(import_exception); @@ -6255,12 +6414,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { wasm_interp_call_func_native(module, exec_env, cur_func, prev_frame); +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + if (is_return_call) { + /* the frame was freed before tail calling and + the prev_frame was set as exec_env's cur_frame, + so here we recover context from prev_frame */ + RECOVER_CONTEXT(prev_frame); + } + else +#endif + { + prev_frame = frame->prev_frame; + cur_func = frame->function; + UPDATE_ALL_FROM_FRAME(); + } } - prev_frame = frame->prev_frame; - cur_func = frame->function; - UPDATE_ALL_FROM_FRAME(); - /* update memory size, no need to update memory ptr as it isn't changed in wasm_enlarge_memory */ #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 21412046e..417e3b016 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1501,6 +1501,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMStringviewIterObjectRef stringview_iter_obj; #endif #endif +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + bool is_return_call = false; +#endif #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OPCODE(op) &&HANDLE_##op @@ -1693,7 +1696,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* clang-format off */ #if WASM_ENABLE_GC == 0 - fidx = tbl_inst->elems[val]; + fidx = (uint32)tbl_inst->elems[val]; if (fidx == (uint32)-1) { wasm_set_exception(module, "uninitialized element"); goto got_exception; @@ -1733,8 +1736,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } #else - if (cur_type->min_type_idx_normalized - != cur_func_type->min_type_idx_normalized) { + if (!wasm_func_type_is_super_of(cur_type, cur_func_type)) { wasm_set_exception(module, "indirect call type mismatch"); goto got_exception; } @@ -5618,6 +5620,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { frame = prev_frame; frame_ip = frame->ip; +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + is_return_call = false; +#endif goto call_func_from_entry; } @@ -5766,6 +5771,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, FREE_FRAME(exec_env, frame); frame_ip += cur_func->param_count * sizeof(int16); wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)prev_frame); + is_return_call = true; goto call_func_from_entry; } #endif /* WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 */ @@ -5838,6 +5844,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } SYNC_ALL_TO_FRAME(); prev_frame = frame; +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + is_return_call = false; +#endif } call_func_from_entry: @@ -5855,9 +5864,20 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, prev_frame); } - prev_frame = frame->prev_frame; - cur_func = frame->function; - UPDATE_ALL_FROM_FRAME(); +#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 + if (is_return_call) { + /* the frame was freed before tail calling and + the prev_frame was set as exec_env's cur_frame, + so here we recover context from prev_frame */ + RECOVER_CONTEXT(prev_frame); + } + else +#endif + { + prev_frame = frame->prev_frame; + cur_func = frame->function; + UPDATE_ALL_FROM_FRAME(); + } /* update memory size, no need to update memory ptr as it isn't changed in wasm_enlarge_memory */ diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index c440ba586..513484fce 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -45,6 +45,16 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) } } +#if WASM_ENABLE_MEMORY64 != 0 +static void +set_error_buf_mem_offset_out_of_range(char *error_buf, uint32 error_buf_size) +{ + if (error_buf != NULL) { + snprintf(error_buf, error_buf_size, "offset out of range"); + } +} +#endif + static void set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, ...) { @@ -102,6 +112,7 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, #define skip_leb_int64(p, p_end) skip_leb(p) #define skip_leb_uint32(p, p_end) skip_leb(p) #define skip_leb_int32(p, p_end) skip_leb(p) +#define skip_leb_mem_offset(p, p_end) skip_leb(p) static bool read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, @@ -139,7 +150,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, } else if (sign && maxbits == 32) { if (shift < maxbits) { - /* Sign extend, second highest bit is the sign bit */ + /* Sign extend, second-highest bit is the sign bit */ if ((uint8)byte & 0x40) result |= (~((uint64)0)) << shift; } @@ -154,7 +165,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, } else if (sign && maxbits == 64) { if (shift < maxbits) { - /* Sign extend, second highest bit is the sign bit */ + /* Sign extend, second-highest bit is the sign bit */ if ((uint8)byte & 0x40) result |= (~((uint64)0)) << shift; } @@ -191,6 +202,21 @@ fail: res = (int64)res64; \ } while (0) +#if WASM_ENABLE_MEMORY64 != 0 +#define read_leb_mem_offset(p, p_end, res) \ + do { \ + uint64 res64; \ + if (!read_leb((uint8 **)&p, p_end, is_memory64 ? 64 : 32, false, \ + &res64, error_buf, error_buf_size)) { \ + set_error_buf_mem_offset_out_of_range(error_buf, error_buf_size); \ + goto fail; \ + } \ + res = (mem_offset_t)res64; \ + } while (0) +#else +#define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res) +#endif + #define read_leb_uint32(p, p_end, res) \ do { \ uint64 res64; \ @@ -368,10 +394,10 @@ memory_realloc(void *mem_old, uint32 size_old, uint32 size_new, char *error_buf, #if WASM_ENABLE_GC != 0 static bool -check_type_index(const WASMModule *module, uint32 type_index, char *error_buf, - uint32 error_buf_size) +check_type_index(const WASMModule *module, uint32 type_count, uint32 type_index, + char *error_buf, uint32 error_buf_size) { - if (type_index >= module->type_count) { + if (type_index >= type_count) { set_error_buf_v(error_buf, error_buf_size, "unknown type %d", type_index); return false; @@ -383,7 +409,8 @@ static bool check_array_type(const WASMModule *module, uint32 type_index, char *error_buf, uint32 error_buf_size) { - if (!check_type_index(module, type_index, error_buf, error_buf_size)) { + if (!check_type_index(module, module->type_count, type_index, error_buf, + error_buf_size)) { return false; } if (module->types[type_index]->type_flag != WASM_TYPE_ARRAY) { @@ -749,8 +776,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!is_byte_a_type(type1)) { p--; read_leb_uint32(p, p_end, type_idx); - if (!check_type_index(module, type_idx, error_buf, - error_buf_size)) + if (!check_type_index(module, module->type_count, type_idx, + error_buf, error_buf_size)) goto fail; wasm_set_refheaptype_typeidx(&cur_ref_type.ref_ht_typeidx, @@ -876,7 +903,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, uint32 field_count; read_leb_uint32(p, p_end, type_idx); - if (!check_type_index(module, type_idx, error_buf, + if (!check_type_index(module, module->type_count, + type_idx, error_buf, error_buf_size)) { goto fail; } @@ -940,7 +968,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, read_leb_uint32(p, p_end, cur_value.type_index); type_idx = cur_value.type_index; - if (!check_type_index(module, type_idx, error_buf, + if (!check_type_index(module, module->type_count, + type_idx, error_buf, error_buf_size)) { goto fail; } @@ -975,7 +1004,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, read_leb_uint32(p, p_end, cur_value.type_index); type_idx = cur_value.type_index; - if (!check_type_index(module, type_idx, error_buf, + if (!check_type_index(module, module->type_count, + type_idx, error_buf, error_buf_size)) { goto fail; } @@ -1249,6 +1279,13 @@ destroy_array_type(WASMArrayType *type) static void destroy_wasm_type(WASMType *type) { + if (type->ref_count > 1) { + /* The type is referenced by other types + of current wasm module */ + type->ref_count--; + return; + } + if (type->type_flag == WASM_TYPE_FUNC) destroy_func_type((WASMFuncType *)type); else if (type->type_flag == WASM_TYPE_STRUCT) @@ -1263,8 +1300,9 @@ destroy_wasm_type(WASMType *type) /* Resolve (ref null ht) or (ref ht) */ static bool resolve_reftype_htref(const uint8 **p_buf, const uint8 *buf_end, - WASMModule *module, bool nullable, WASMRefType *ref_type, - char *error_buf, uint32 error_buf_size) + WASMModule *module, uint32 type_count, bool nullable, + WASMRefType *ref_type, char *error_buf, + uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; @@ -1275,8 +1313,9 @@ resolve_reftype_htref(const uint8 **p_buf, const uint8 *buf_end, if (wasm_is_refheaptype_typeidx(&ref_type->ref_ht_common)) { /* heap type is (type i), i : typeidx, >= 0 */ - if (!check_type_index(module, ref_type->ref_ht_typeidx.type_idx, - error_buf, error_buf_size)) { + if (!check_type_index(module, type_count, + ref_type->ref_ht_typeidx.type_idx, error_buf, + error_buf_size)) { return false; } } @@ -1294,9 +1333,10 @@ fail: static bool resolve_value_type(const uint8 **p_buf, const uint8 *buf_end, - WASMModule *module, bool *p_need_ref_type_map, - WASMRefType *ref_type, bool allow_packed_type, - char *error_buf, uint32 error_buf_size) + WASMModule *module, uint32 type_count, + bool *p_need_ref_type_map, WASMRefType *ref_type, + bool allow_packed_type, char *error_buf, + uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; uint8 type; @@ -1308,8 +1348,8 @@ resolve_value_type(const uint8 **p_buf, const uint8 *buf_end, if (wasm_is_reftype_htref_nullable(type)) { /* (ref null ht) */ - if (!resolve_reftype_htref(&p, p_end, module, true, ref_type, error_buf, - error_buf_size)) + if (!resolve_reftype_htref(&p, p_end, module, type_count, true, + ref_type, error_buf, error_buf_size)) return false; if (!wasm_is_refheaptype_common(&ref_type->ref_ht_common)) *p_need_ref_type_map = true; @@ -1325,8 +1365,8 @@ resolve_value_type(const uint8 **p_buf, const uint8 *buf_end, } else if (wasm_is_reftype_htref_non_nullable(type)) { /* (ref ht) */ - if (!resolve_reftype_htref(&p, p_end, module, false, ref_type, - error_buf, error_buf_size)) + if (!resolve_reftype_htref(&p, p_end, module, type_count, false, + ref_type, error_buf, error_buf_size)) return false; *p_need_ref_type_map = true; #if WASM_ENABLE_STRINGREF != 0 @@ -1375,7 +1415,8 @@ reftype_set_insert(HashMap *ref_type_set, const WASMRefType *ref_type, static bool resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, - uint32 type_idx, char *error_buf, uint32 error_buf_size) + uint32 type_count, uint32 type_idx, char *error_buf, + uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end, *p_org; uint32 param_count, result_count, i, j = 0; @@ -1391,8 +1432,9 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, param_count); p_org = p; for (i = 0; i < param_count; i++) { - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, - &ref_type, false, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, type_count, + &need_ref_type_map, &ref_type, false, error_buf, + error_buf_size)) { return false; } if (need_ref_type_map) @@ -1401,8 +1443,9 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, result_count); for (i = 0; i < result_count; i++) { - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, - &ref_type, false, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, type_count, + &need_ref_type_map, &ref_type, false, error_buf, + error_buf_size)) { return false; } if (need_ref_type_map) { @@ -1442,8 +1485,9 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, } for (i = 0; i < param_count; i++) { - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, - &ref_type, false, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, type_count, + &need_ref_type_map, &ref_type, false, error_buf, + error_buf_size)) { goto fail; } type->types[i] = ref_type.ref_type; @@ -1459,8 +1503,9 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, result_count); for (i = 0; i < result_count; i++) { - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, - &ref_type, false, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, type_count, + &need_ref_type_map, &ref_type, false, error_buf, + error_buf_size)) { goto fail; } type->types[param_count + i] = ref_type.ref_type; @@ -1495,24 +1540,12 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, #endif #if WASM_ENABLE_WAMR_COMPILER != 0 - for (i = 0; i < type->param_count + type->result_count; i++) { + for (i = 0; i < (uint32)(type->param_count + type->result_count); i++) { if (type->types[i] == VALUE_TYPE_V128) module->is_simd_used = true; } #endif - /* Calculate the minimal type index of the type equal to this type */ - type->min_type_idx_normalized = type_idx; - for (i = 0; i < type_idx; i++) { - WASMFuncType *func_type = (WASMFuncType *)module->types[i]; - if (func_type->base_type.type_flag == WASM_TYPE_FUNC - && wasm_func_type_equal(type, func_type, module->types, - type_idx + 1)) { - type->min_type_idx_normalized = i; - break; - } - } - *p_buf = p; module->types[type_idx] = (WASMType *)type; @@ -1526,8 +1559,8 @@ fail: static bool resolve_struct_type(const uint8 **p_buf, const uint8 *buf_end, - WASMModule *module, uint32 type_idx, char *error_buf, - uint32 error_buf_size) + WASMModule *module, uint32 type_count, uint32 type_idx, + char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end, *p_org; uint32 field_count, ref_type_map_count = 0, ref_field_count = 0; @@ -1543,8 +1576,9 @@ resolve_struct_type(const uint8 **p_buf, const uint8 *buf_end, read_leb_uint32(p, p_end, field_count); p_org = p; for (i = 0; i < field_count; i++) { - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, - &ref_type, true, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, type_count, + &need_ref_type_map, &ref_type, true, error_buf, + error_buf_size)) { return false; } if (need_ref_type_map) @@ -1591,8 +1625,9 @@ resolve_struct_type(const uint8 **p_buf, const uint8 *buf_end, offset = (uint32)offsetof(WASMStructObject, field_data); for (i = 0; i < field_count; i++) { - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, - &ref_type, true, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, type_count, + &need_ref_type_map, &ref_type, true, error_buf, + error_buf_size)) { goto fail; } type->fields[i].field_type = ref_type.ref_type; @@ -1645,8 +1680,8 @@ fail: static bool resolve_array_type(const uint8 **p_buf, const uint8 *buf_end, - WASMModule *module, uint32 type_idx, char *error_buf, - uint32 error_buf_size) + WASMModule *module, uint32 type_count, uint32 type_idx, + char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; uint8 mutable; @@ -1654,8 +1689,8 @@ resolve_array_type(const uint8 **p_buf, const uint8 *buf_end, WASMRefType ref_type; WASMArrayType *type = NULL; - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, &ref_type, - true, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, type_count, &need_ref_type_map, + &ref_type, true, error_buf, error_buf_size)) { return false; } @@ -1704,7 +1739,8 @@ init_ref_type(WASMModule *module, WASMRefType *ref_type, bool nullable, int32 heap_type, char *error_buf, uint32 error_buf_size) { if (heap_type >= 0) { - if (!check_type_index(module, heap_type, error_buf, error_buf_size)) { + if (!check_type_index(module, module->type_count, heap_type, error_buf, + error_buf_size)) { return false; } wasm_set_refheaptype_typeidx(&ref_type->ref_ht_typeidx, nullable, @@ -1903,8 +1939,8 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } #else /* else of WASM_ENABLE_GC == 0 */ for (i = 0; i < type_count; i++) { - uint32 super_type_count = 0, parent_type_idx = (uint32)-1, - rec_count = 1, j; + uint32 super_type_count = 0, parent_type_idx = (uint32)-1; + uint32 rec_count = 1, j; bool is_sub_final = true; CHECK_BUF(p, p_end, 1); @@ -1916,10 +1952,22 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (rec_count > 1) { uint64 new_total_size; + /* integer overflow */ + if (rec_count - 1 > UINT32_MAX - module->type_count) { + set_error_buf(error_buf, error_buf_size, + "recursive type count too large"); + return false; + } module->type_count += rec_count - 1; new_total_size = sizeof(WASMFuncType *) * (uint64)module->type_count; - MEM_REALLOC(module->types, total_size, new_total_size); + if (new_total_size > UINT32_MAX) { + set_error_buf(error_buf, error_buf_size, + "allocate memory failed"); + return false; + } + MEM_REALLOC(module->types, (uint32)total_size, + (uint32)new_total_size); total_size = new_total_size; } @@ -1972,6 +2020,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (flag == DEFINED_TYPE_FUNC) { if (!resolve_func_type(&p, buf_end, module, + processed_type_count + rec_count, processed_type_count + j, error_buf, error_buf_size)) { return false; @@ -1979,6 +2028,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } else if (flag == DEFINED_TYPE_STRUCT) { if (!resolve_struct_type(&p, buf_end, module, + processed_type_count + rec_count, processed_type_count + j, error_buf, error_buf_size)) { return false; @@ -1986,6 +2036,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } else if (flag == DEFINED_TYPE_ARRAY) { if (!resolve_array_type(&p, buf_end, module, + processed_type_count + rec_count, processed_type_count + j, error_buf, error_buf_size)) { return false; @@ -1999,13 +2050,13 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, cur_type = module->types[processed_type_count + j]; + cur_type->ref_count = 1; cur_type->parent_type_idx = parent_type_idx; cur_type->is_sub_final = is_sub_final; - if (rec_count > 1) { - cur_type->rec_count = rec_count; - cur_type->rec_idx = j; - } + cur_type->rec_count = rec_count; + cur_type->rec_idx = j; + cur_type->rec_begin_type_idx = processed_type_count; } /* resolve subtyping relationship in current rec group */ @@ -2017,6 +2068,11 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->types[cur_type->parent_type_idx]; cur_type->parent_type = parent_type; cur_type->root_type = parent_type->root_type; + if (parent_type->inherit_depth == UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "parent type's inherit depth too large"); + return false; + } cur_type->inherit_depth = parent_type->inherit_depth + 1; } else { @@ -2042,6 +2098,49 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } } + /* If there is already an equivalence type or a group of equivalence + recursive types created, use it or them instead */ + for (j = 0; j < processed_type_count;) { + WASMType *src_type = module->types[j]; + WASMType *cur_type = module->types[processed_type_count]; + uint32 k, src_rec_count; + + src_rec_count = src_type->rec_count; + if (src_rec_count != rec_count) { + /* no type equivalence */ + j += src_rec_count; + continue; + } + + for (k = 0; k < rec_count; k++) { + src_type = module->types[j + k]; + cur_type = module->types[processed_type_count + k]; + if (!wasm_type_equal(src_type, cur_type, module->types, + module->type_count)) { + break; + } + } + if (k < rec_count) { + /* no type equivalence */ + j += src_rec_count; + continue; + } + + /* type equivalence */ + for (k = 0; k < rec_count; k++) { + if (module->types[j + k]->ref_count == UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "wasm type's ref count too large"); + return false; + } + destroy_wasm_type(module->types[processed_type_count + k]); + module->types[processed_type_count + k] = + module->types[j + k]; + module->types[j + k]->ref_count++; + } + break; + } + if (rec_count > 1) { LOG_VERBOSE("Finished processing rec group [%d-%d]", processed_type_count, @@ -2473,8 +2572,9 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, return false; } #else /* else of WASM_ENABLE_GC == 0 */ - if (!resolve_value_type(&p, p_end, parent_module, &need_ref_type_map, - &ref_type, false, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, parent_module, parent_module->type_count, + &need_ref_type_map, &ref_type, false, error_buf, + error_buf_size)) { return false; } if (wasm_is_reftype_htref_non_nullable(ref_type.ref_type)) { @@ -2582,31 +2682,92 @@ fail: } static bool -check_memory_init_size(uint32 init_size, char *error_buf, uint32 error_buf_size) +check_memory_init_size(bool is_memory64, uint32 init_size, char *error_buf, + uint32 error_buf_size) { - if (init_size > DEFAULT_MAX_PAGES) { + uint32 default_max_size = + is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; + + if (!is_memory64 && init_size > default_max_size) { set_error_buf(error_buf, error_buf_size, "memory size must be at most 65536 pages (4GiB)"); return false; } +#if WASM_ENABLE_MEMORY64 != 0 + else if (is_memory64 && init_size > default_max_size) { + set_error_buf( + error_buf, error_buf_size, + "memory size must be at most 4,294,967,295 pages (274 Terabyte)"); + return false; + } +#endif return true; } static bool -check_memory_max_size(uint32 init_size, uint32 max_size, char *error_buf, - uint32 error_buf_size) +check_memory_max_size(bool is_memory64, uint32 init_size, uint32 max_size, + char *error_buf, uint32 error_buf_size) { + uint32 default_max_size = + is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; + if (max_size < init_size) { set_error_buf(error_buf, error_buf_size, "size minimum must not be greater than maximum"); return false; } - if (max_size > DEFAULT_MAX_PAGES) { + if (!is_memory64 && max_size > default_max_size) { set_error_buf(error_buf, error_buf_size, "memory size must be at most 65536 pages (4GiB)"); return false; } +#if WASM_ENABLE_MEMORY64 != 0 + else if (is_memory64 && max_size > default_max_size) { + set_error_buf( + error_buf, error_buf_size, + "memory size must be at most 4,294,967,295 pages (274 Terabyte)"); + return false; + } +#endif + + return true; +} + +static bool +check_memory_flag(const uint8 mem_flag, char *error_buf, uint32 error_buf_size) +{ + /* Check whether certain features indicated by mem_flag are enabled in + * runtime */ + if (mem_flag > MAX_PAGE_COUNT_FLAG) { +#if WASM_ENABLE_SHARED_MEMORY == 0 + if (mem_flag & SHARED_MEMORY_FLAG) { + LOG_VERBOSE("shared memory flag was found, please enable shared " + "memory, lib-pthread or lib-wasi-threads"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } +#endif +#if WASM_ENABLE_MEMORY64 == 0 + if (mem_flag & MEMORY64_FLAG) { + LOG_VERBOSE("memory64 flag was found, please enable memory64"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } +#endif + } + + if (mem_flag > MAX_PAGE_COUNT_FLAG + SHARED_MEMORY_FLAG + MEMORY64_FLAG) { + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } + else if ((mem_flag & SHARED_MEMORY_FLAG) + && !(mem_flag & MAX_PAGE_COUNT_FLAG)) { + set_error_buf(error_buf, error_buf_size, + "shared memory must have maximum"); + return false; + } + return true; } @@ -2616,15 +2777,16 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, const char *memory_name, WASMMemoryImport *memory, char *error_buf, uint32 error_buf_size) { - const uint8 *p = *p_buf, *p_end = buf_end; + const uint8 *p = *p_buf, *p_end = buf_end, *p_org; #if WASM_ENABLE_APP_FRAMEWORK != 0 uint32 pool_size = wasm_runtime_memory_pool_size(); uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT / DEFAULT_NUM_BYTES_PER_PAGE; #else - uint32 max_page_count = DEFAULT_MAX_PAGES; + uint32 max_page_count; #endif /* WASM_ENABLE_APP_FRAMEWORK */ - uint32 declare_max_page_count_flag = 0; + uint32 mem_flag = 0; + bool is_memory64 = false; uint32 declare_init_page_count = 0; uint32 declare_max_page_count = 0; #if WASM_ENABLE_MULTI_MODULE != 0 @@ -2632,16 +2794,31 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *linked_memory = NULL; #endif - read_leb_uint32(p, p_end, declare_max_page_count_flag); + p_org = p; + 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"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } + + if (!check_memory_flag(mem_flag, error_buf, error_buf_size)) { + return false; + } + read_leb_uint32(p, p_end, declare_init_page_count); - if (!check_memory_init_size(declare_init_page_count, error_buf, + if (!check_memory_init_size(is_memory64, declare_init_page_count, error_buf, error_buf_size)) { return false; } - if (declare_max_page_count_flag & 1) { +#if WASM_ENABLE_APP_FRAMEWORK == 0 + max_page_count = is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; +#endif + if (mem_flag & MAX_PAGE_COUNT_FLAG) { read_leb_uint32(p, p_end, declare_max_page_count); - if (!check_memory_max_size(declare_init_page_count, + if (!check_memory_max_size(is_memory64, declare_init_page_count, declare_max_page_count, error_buf, error_buf_size)) { return false; @@ -2664,7 +2841,7 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, #if WASM_ENABLE_LIB_WASI_THREADS != 0 /* Avoid memory import failure when wasi-threads is enabled and the memory is shared */ - if (!(declare_max_page_count_flag & 2)) + if (!(mem_flag & SHARED_MEMORY_FLAG)) return false; #else return false; @@ -2712,7 +2889,7 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, } /* now we believe all declaration are ok */ - memory->flags = declare_max_page_count_flag; + memory->flags = mem_flag; memory->init_page_count = declare_init_page_count; memory->max_page_count = declare_max_page_count; memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; @@ -2832,8 +3009,9 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, declare_type = read_uint8(p); declare_mutable = read_uint8(p); #else - if (!resolve_value_type(&p, p_end, parent_module, &need_ref_type_map, - &ref_type, false, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, parent_module, parent_module->type_count, + &need_ref_type_map, &ref_type, false, error_buf, + error_buf_size)) { return false; } declare_type = ref_type.ref_type; @@ -2935,8 +3113,9 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, return false; } #else /* else of WASM_ENABLE_GC == 0 */ - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, &ref_type, - false, error_buf, error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, module->type_count, + &need_ref_type_map, &ref_type, false, error_buf, + error_buf_size)) { return false; } table->elem_type = ref_type.ref_type; @@ -3013,53 +3192,34 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT / DEFAULT_NUM_BYTES_PER_PAGE; #else - uint32 max_page_count = DEFAULT_MAX_PAGES; + uint32 max_page_count; #endif + bool is_memory64 = false; p_org = p; read_leb_uint32(p, p_end, memory->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 (memory->flags > 1) { - if (memory->flags & 2) { - set_error_buf(error_buf, error_buf_size, - "shared memory flag was found, " - "please enable shared memory, lib-pthread " - "or lib-wasi-threads"); - } - else { - set_error_buf(error_buf, error_buf_size, "invalid memory flags"); - } - return false; - } -#else + is_memory64 = memory->flags & MEMORY64_FLAG; if (p - p_org > 1) { + LOG_VERBOSE("integer representation too long"); set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } - if (memory->flags > 3) { - set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + + if (!check_memory_flag(memory->flags, error_buf, error_buf_size)) { return false; } - else if (memory->flags == 2) { - set_error_buf(error_buf, error_buf_size, - "shared memory must have maximum"); - return false; - } -#endif read_leb_uint32(p, p_end, memory->init_page_count); - if (!check_memory_init_size(memory->init_page_count, error_buf, + if (!check_memory_init_size(is_memory64, memory->init_page_count, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_APP_FRAMEWORK == 0 + max_page_count = is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; +#endif if (memory->flags & 1) { read_leb_uint32(p, p_end, memory->max_page_count); - if (!check_memory_max_size(memory->init_page_count, + if (!check_memory_max_size(is_memory64, memory->init_page_count, memory->max_page_count, error_buf, error_buf_size)) return false; @@ -3440,7 +3600,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, type_index_org = type_index; #endif -#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) +#if (WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0) \ + && WASM_ENABLE_GC == 0 type_index = wasm_get_smallest_type_idx( module->types, module->type_count, type_index); #endif @@ -3481,8 +3642,9 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, #endif #else if (!resolve_value_type(&p_code, buf_code_end, module, - &need_ref_type_map, &ref_type, false, - error_buf, error_buf_size)) { + module->type_count, &need_ref_type_map, + &ref_type, false, error_buf, + error_buf_size)) { return false; } local_count += sub_local_count; @@ -3568,8 +3730,9 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, } #else if (!resolve_value_type(&p_code, buf_code_end, module, - &need_ref_type_map, &ref_type, false, - error_buf, error_buf_size)) { + module->type_count, &need_ref_type_map, + &ref_type, false, error_buf, + error_buf_size)) { return false; } if (need_ref_type_map) { @@ -3827,9 +3990,9 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, global->type = read_uint8(p); mutable = read_uint8(p); #else - if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, - &ref_type, false, error_buf, - error_buf_size)) { + if (!resolve_value_type(&p, p_end, module, module->type_count, + &need_ref_type_map, &ref_type, false, + error_buf, error_buf_size)) { return false; } global->type = ref_type.ref_type; @@ -4135,8 +4298,8 @@ load_elem_type(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, #else p--; if (!resolve_value_type((const uint8 **)&p, p_end, module, - &need_ref_type_map, &elem_ref_type, false, - error_buf, error_buf_size)) { + module->type_count, &need_ref_type_map, + &elem_ref_type, false, error_buf, error_buf_size)) { return false; } if (!wasm_is_type_reftype(elem_ref_type.ref_type)) { @@ -4450,6 +4613,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, bool is_passive = false; uint32 mem_flag; #endif + uint8 mem_offset_type; read_leb_uint32(p, p_end, data_seg_count); @@ -4515,11 +4679,35 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, } #endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_BULK_MEMORY != 0 + if (!is_passive) +#endif + { +#if WASM_ENABLE_MEMORY64 != 0 + /* 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.memory.flags; + } + else { + memory_flag = + module + ->memories[mem_index - module->import_memory_count] + .flags; + } + mem_offset_type = memory_flag & MEMORY64_FLAG ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#else + mem_offset_type = VALUE_TYPE_I32; +#endif + } + #if WASM_ENABLE_BULK_MEMORY != 0 if (!is_passive) #endif if (!load_init_expr(module, &p, p_end, &init_expr, - VALUE_TYPE_I32, NULL, error_buf, + mem_offset_type, NULL, error_buf, error_buf_size)) return false; @@ -5465,8 +5653,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, *buf_func = NULL, *buf_func_end = NULL; WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL; WASMGlobal *aux_stack_top_global = NULL, *global; - uint64 aux_data_end = (uint64)-1, aux_heap_base = (uint64)-1, - aux_stack_top = (uint64)-1; + uint64 aux_data_end = (uint64)-1LL, aux_heap_base = (uint64)-1LL, + aux_stack_top = (uint64)-1LL; uint32 global_index, func_index, i; uint32 aux_data_end_global_index = (uint32)-1; uint32 aux_heap_base_global_index = (uint32)-1; @@ -5606,7 +5794,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, aux_heap_base_global = global; aux_heap_base = (uint64)(uint32)global->init_expr.u.i32; aux_heap_base_global_index = export->index; - LOG_VERBOSE("Found aux __heap_base global, value: %d", + LOG_VERBOSE("Found aux __heap_base global, value: %" PRIu64, aux_heap_base); } } @@ -5619,7 +5807,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, aux_data_end_global = global; aux_data_end = (uint64)(uint32)global->init_expr.u.i32; aux_data_end_global_index = export->index; - LOG_VERBOSE("Found aux __data_end global, value: %d", + LOG_VERBOSE("Found aux __data_end global, value: %" PRIu64, aux_data_end); aux_data_end = align_uint64(aux_data_end, 16); @@ -5669,10 +5857,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, aux_stack_top > aux_data_end ? (uint32)(aux_stack_top - aux_data_end) : (uint32)aux_stack_top; - LOG_VERBOSE("Found aux stack top global, value: %d, " - "global index: %d, stack size: %d", - aux_stack_top, global_index, - module->aux_stack_size); + LOG_VERBOSE( + "Found aux stack top global, value: %" PRIu64 ", " + "global index: %d, stack size: %d", + aux_stack_top, global_index, + module->aux_stack_size); break; } } @@ -5820,9 +6009,10 @@ load_from_sections(WASMModule *module, WASMSection *sections, * memory_import->init_page_count; if (shrunk_memory_size <= init_memory_size) { /* Reset memory info to decrease memory usage */ - memory_import->num_bytes_per_page = shrunk_memory_size; + memory_import->num_bytes_per_page = + (uint32)shrunk_memory_size; memory_import->init_page_count = 1; - LOG_VERBOSE("Shrink import memory size to %d", + LOG_VERBOSE("Shrink import memory size to %" PRIu64, shrunk_memory_size); } } @@ -5833,9 +6023,9 @@ load_from_sections(WASMModule *module, WASMSection *sections, * memory->init_page_count; if (shrunk_memory_size <= init_memory_size) { /* Reset memory info to decrease memory usage */ - memory->num_bytes_per_page = shrunk_memory_size; + memory->num_bytes_per_page = (uint32)shrunk_memory_size; memory->init_page_count = 1; - LOG_VERBOSE("Shrink memory size to %d", + LOG_VERBOSE("Shrink memory size to %" PRIu64, shrunk_memory_size); } } @@ -5920,7 +6110,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, } static WASMModule * -create_module(char *error_buf, uint32 error_buf_size) +create_module(char *name, char *error_buf, uint32 error_buf_size) { WASMModule *module = loader_malloc(sizeof(WASMModule), error_buf, error_buf_size); @@ -5935,7 +6125,7 @@ create_module(char *error_buf, uint32 error_buf_size) /* Set start_function to -1, means no start function */ module->start_function = (uint32)-1; - module->name = ""; + module->name = name; #if WASM_ENABLE_FAST_INTERP == 0 module->br_table_cache_list = &module->br_table_cache_list_head; @@ -6015,7 +6205,7 @@ WASMModule * wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf, uint32 error_buf_size) { - WASMModule *module = create_module(error_buf, error_buf_size); + WASMModule *module = create_module("", error_buf, error_buf_size); if (!module) return NULL; @@ -6356,9 +6546,9 @@ wasm_loader_load(uint8 *buf, uint32 size, #if WASM_ENABLE_MULTI_MODULE != 0 bool main_module, #endif - char *error_buf, uint32 error_buf_size) + const LoadArgs *args, char *error_buf, uint32 error_buf_size) { - WASMModule *module = create_module(error_buf, error_buf_size); + WASMModule *module = create_module(args->name, error_buf, error_buf_size); if (!module) { return NULL; } @@ -6545,7 +6735,7 @@ wasm_loader_unload(WASMModule *module) #if WASM_ENABLE_STRINGREF != 0 if (module->string_literal_ptrs) { - wasm_runtime_free(module->string_literal_ptrs); + wasm_runtime_free((void *)module->string_literal_ptrs); } if (module->string_literal_lengths) { wasm_runtime_free(module->string_literal_lengths); @@ -6979,8 +7169,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: - skip_leb_uint32(p, p_end); /* align */ - skip_leb_uint32(p, p_end); /* offset */ + skip_leb_uint32(p, p_end); /* align */ + skip_leb_mem_offset(p, p_end); /* offset */ break; case WASM_OP_MEMORY_SIZE: @@ -7326,6 +7516,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) case WASM_OP_SIMD_PREFIX: { + /* TODO: memory64 offset type changes */ uint32 opcode1; read_leb_uint32(p, p_end, opcode1); @@ -7422,6 +7613,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, #if WASM_ENABLE_SHARED_MEMORY != 0 case WASM_OP_ATOMIC_PREFIX: { + /* TODO: memory64 offset type changes */ uint32 opcode1; /* atomic_op (u32_leb) + memarg (2 u32_leb) */ @@ -7431,8 +7623,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, opcode = (uint8)opcode1; if (opcode != WASM_OP_ATOMIC_FENCE) { - skip_leb_uint32(p, p_end); /* align */ - skip_leb_uint32(p, p_end); /* offset */ + skip_leb_uint32(p, p_end); /* align */ + skip_leb_mem_offset(p, p_end); /* offset */ } else { /* atomic.fence doesn't have memarg */ @@ -8245,12 +8437,12 @@ wasm_loader_pop_nullable_ht(WASMLoaderContext *ctx, uint8 *p_type, } /* Convert to related (ref ht) and return */ - if ((type >= REF_TYPE_EQREF && type <= REF_TYPE_FUNCREF) - || (type >= REF_TYPE_NULLREF && type <= REF_TYPE_I31REF)) { - /* Return (ref func/extern/any/eq/i31/nofunc/noextern/struct/array/none) + if (type >= REF_TYPE_ARRAYREF && type <= REF_TYPE_NULLFUNCREF) { + /* Return (ref array/struct/i31/eq/any/extern/func/none/noextern/nofunc) */ wasm_set_refheaptype_common(&ref_ht_ret->ref_ht_common, false, - HEAP_TYPE_FUNC + (type - REF_TYPE_FUNCREF)); + HEAP_TYPE_ARRAY + + (type - REF_TYPE_ARRAYREF)); type = ref_ht_ret->ref_type; } else if (wasm_is_reftype_htref_nullable(type) @@ -8448,11 +8640,11 @@ fail: wasm_loader_emit_ptr(loader_ctx, NULL); \ } while (0) -#define emit_br_info(frame_csp) \ - do { \ - if (!wasm_loader_emit_br_info(loader_ctx, frame_csp, error_buf, \ - error_buf_size)) \ - goto fail; \ +#define emit_br_info(frame_csp, is_br) \ + do { \ + if (!wasm_loader_emit_br_info(loader_ctx, frame_csp, is_br, error_buf, \ + error_buf_size)) \ + goto fail; \ } while (0) #define LAST_OP_OUTPUT_I32() \ @@ -8846,7 +9038,7 @@ apply_label_patch(WASMLoaderContext *ctx, uint8 depth, uint8 patch_type) static bool wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, - char *error_buf, uint32 error_buf_size) + bool is_br, char *error_buf, uint32 error_buf_size) { /* br info layout: * a) arity of target block @@ -8907,6 +9099,8 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, /* Part e */ dynamic_offset = frame_csp->dynamic_offset + wasm_get_cell_num(types, arity); + if (is_br) + ctx->dynamic_offset = dynamic_offset; for (i = (int32)arity - 1; i >= 0; i--) { cell = (uint8)wasm_value_type_cell_num(types[i]); dynamic_offset -= cell; @@ -9332,6 +9526,8 @@ fail: #define PUSH_EXTERNREF() TEMPLATE_PUSH(EXTERNREF) #define PUSH_REF(Type) TEMPLATE_PUSH_REF(Type) #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 POP_I32() TEMPLATE_POP(I32) #define POP_F32() TEMPLATE_POP(F32) @@ -9341,6 +9537,7 @@ fail: #define POP_FUNCREF() TEMPLATE_POP(FUNCREF) #define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF) #define POP_STRINGREF() TEMPLATE_POP(STRINGREF) +#define POP_MEM_OFFSET() TEMPLATE_POP_REF(mem_offset_type) #if WASM_ENABLE_FAST_INTERP != 0 @@ -9774,8 +9971,8 @@ check_memory_align_equal(uint8 opcode, uint32 align, char *error_buf, #endif /* end of WASM_ENABLE_SHARED_MEMORY */ static bool -wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, - bool is_br_table, char *error_buf, uint32 error_buf_size) +wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, uint8 opcode, + char *error_buf, uint32 error_buf_size) { BranchBlock *target_block, *cur_block; BlockType *target_block_type; @@ -9872,7 +10069,7 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, /* Backup stack data since it may be changed in the below push operations, and the stack data may be used when checking other target blocks of opcode br_table */ - if (is_br_table) { + if (opcode == WASM_OP_BR_TABLE) { uint64 total_size; frame_ref_after_popped = loader_ctx->frame_ref; @@ -9936,13 +10133,13 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, } #if WASM_ENABLE_FAST_INTERP != 0 - emit_br_info(target_block); + emit_br_info(target_block, opcode == WASM_OP_BR); #endif /* Restore the stack data, note that frame_ref_bottom, frame_reftype_map_bottom, frame_offset_bottom may be re-allocated in the above push operations */ - if (is_br_table) { + if (opcode == WASM_OP_BR_TABLE) { uint32 total_size; /* The stack operand num should not be smaller than before @@ -9951,8 +10148,8 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, loader_ctx->stack_cell_num = stack_cell_num_old; loader_ctx->frame_ref = loader_ctx->frame_ref_bottom + stack_cell_num_old; - total_size = (uint32)sizeof(uint8) - * (frame_ref_old - frame_ref_after_popped); + total_size = (uint32)(sizeof(uint8) + * (frame_ref_old - frame_ref_after_popped)); bh_memcpy_s((uint8 *)loader_ctx->frame_ref - total_size, total_size, frame_ref_buf, total_size); @@ -9963,9 +10160,9 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, loader_ctx->reftype_map_num = reftype_map_num_old; loader_ctx->frame_reftype_map = loader_ctx->frame_reftype_map_bottom + reftype_map_num_old; - total_size = - (uint32)sizeof(WASMRefTypeMap) - * (frame_reftype_map_old - frame_reftype_map_after_popped); + total_size = (uint32)(sizeof(WASMRefTypeMap) + * (frame_reftype_map_old + - frame_reftype_map_after_popped)); bh_memcpy_s((uint8 *)loader_ctx->frame_reftype_map - total_size, total_size, frame_reftype_map_buf, total_size); #endif @@ -9973,8 +10170,9 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, #if WASM_ENABLE_FAST_INTERP != 0 loader_ctx->frame_offset = loader_ctx->frame_offset_bottom + stack_cell_num_old; - total_size = (uint32)sizeof(int16) - * (frame_offset_old - frame_offset_after_popped); + total_size = + (uint32)(sizeof(int16) + * (frame_offset_old - frame_offset_after_popped)); bh_memcpy_s((uint8 *)loader_ctx->frame_offset - total_size, total_size, frame_offset_buf, total_size); (loader_ctx->frame_csp - 1)->dynamic_offset = dynamic_offset_old; @@ -10033,7 +10231,7 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, } #if WASM_ENABLE_FAST_INTERP != 0 - emit_br_info(target_block); + emit_br_info(target_block, opcode == WASM_OP_BR); #endif ret = true; @@ -10048,7 +10246,7 @@ fail: #endif #if WASM_ENABLE_FAST_INTERP != 0 if (frame_offset_buf && frame_offset_buf != frame_offset_tmp) - wasm_runtime_free(frame_offset_tmp); + wasm_runtime_free(frame_offset_buf); #endif return ret; @@ -10056,14 +10254,14 @@ fail: static BranchBlock * check_branch_block(WASMLoaderContext *loader_ctx, uint8 **p_buf, uint8 *buf_end, - bool is_br_table, char *error_buf, uint32 error_buf_size) + uint8 opcode, char *error_buf, uint32 error_buf_size) { uint8 *p = *p_buf, *p_end = buf_end; BranchBlock *frame_csp_tmp; uint32 depth; read_leb_uint32(p, p_end, depth); - if (!wasm_loader_check_br(loader_ctx, depth, is_br_table, error_buf, + if (!wasm_loader_check_br(loader_ctx, depth, opcode, error_buf, error_buf_size)) { goto fail; } @@ -10104,7 +10302,7 @@ check_branch_block_for_delegate(WASMLoaderContext *loader_ctx, uint8 **p_buf, } frame_csp_tmp = loader_ctx->frame_csp - depth - 2; #if WASM_ENABLE_FAST_INTERP != 0 - emit_br_info(frame_csp_tmp); + emit_br_info(frame_csp_tmp, false); #endif *p_buf = p; @@ -10508,11 +10706,12 @@ 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; + uint8 *param_types, *local_types, local_type, global_type, mem_offset_type; BlockType func_block_type; uint16 *local_offsets, local_offset; uint32 type_idx, func_idx, local_idx, global_idx, table_idx; - uint32 table_seg_idx, data_seg_idx, count, align, mem_offset, i; + uint32 table_seg_idx, data_seg_idx, count, align, i; + mem_offset_t mem_offset; int32 i32_const = 0; int64 i64_const; uint8 opcode; @@ -10537,6 +10736,19 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, LOG_OP("\nProcessing func | [%d] params | [%d] locals | [%d] return\n", func->param_cell_num, func->local_cell_num, func->ret_cell_num); #endif +#if WASM_ENABLE_MEMORY64 != 0 + bool is_memory64 = false; + /* TODO: multi-memories for now assuming the memory idx type is consistent + * across multi-memories */ + if (module->import_memory_count > 0) + is_memory64 = module->import_memories[0].u.memory.flags & MEMORY64_FLAG; + else if (module->memory_count > 0) + is_memory64 = module->memories[0].flags & MEMORY64_FLAG; + + mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32; +#else + mem_offset_type = VALUE_TYPE_I32; +#endif global_count = module->import_global_count + module->global_count; @@ -10682,7 +10894,8 @@ re_scan: p_org = p; p--; if (!resolve_value_type((const uint8 **)&p, p_end, - module, &need_ref_type_map, + module, module->type_count, + &need_ref_type_map, &wasm_ref_type, false, error_buf, error_buf_size)) { goto fail; @@ -10980,7 +11193,7 @@ re_scan: /* check the target catching block: LABEL_TYPE_CATCH */ if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, false, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) goto fail; @@ -11158,8 +11371,8 @@ re_scan: bh_memcpy_s(loader_ctx->frame_offset, size, block->param_frame_offsets, size); loader_ctx->frame_offset += (size / sizeof(int16)); - loader_ctx->dynamic_offset = block->start_dynamic_offset; } + loader_ctx->dynamic_offset = block->start_dynamic_offset; #endif break; @@ -11267,7 +11480,7 @@ re_scan: case WASM_OP_BR: { if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, false, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) goto fail; @@ -11281,7 +11494,7 @@ re_scan: POP_I32(); if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, false, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) goto fail; @@ -11351,7 +11564,7 @@ re_scan: } if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, true, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) { goto fail; } @@ -11453,6 +11666,15 @@ re_scan: if (opcode == WASM_OP_CALL_REF || opcode == WASM_OP_RETURN_CALL_REF) { read_leb_uint32(p, p_end, type_idx1); + if (!check_type_index(module, module->type_count, type_idx1, + error_buf, error_buf_size)) { + goto fail; + } + if (module->types[type_idx1]->type_flag != WASM_TYPE_FUNC) { + set_error_buf(error_buf, error_buf_size, + "unkown function type"); + goto fail; + } if (!wasm_loader_pop_nullable_typeidx(loader_ctx, &type, &type_idx, error_buf, error_buf_size)) { @@ -11461,8 +11683,8 @@ re_scan: if (type == VALUE_TYPE_ANY) { type_idx = type_idx1; } - if (!check_type_index(module, type_idx, error_buf, - error_buf_size)) { + if (!check_type_index(module, module->type_count, type_idx, + error_buf, error_buf_size)) { goto fail; } if (module->types[type_idx]->type_flag != WASM_TYPE_FUNC) { @@ -11470,7 +11692,9 @@ re_scan: "unkown function type"); goto fail; } - if (type_idx != type_idx1) { + if (!wasm_func_type_is_super_of( + (WASMFuncType *)module->types[type_idx1], + (WASMFuncType *)module->types[type_idx])) { set_error_buf(error_buf, error_buf_size, "function type mismatch"); goto fail; @@ -11910,8 +12134,9 @@ re_scan: #else p_org = p + 1; if (!resolve_value_type((const uint8 **)&p, p_end, module, - &need_ref_type_map, &wasm_ref_type, - false, error_buf, error_buf_size)) { + module->type_count, &need_ref_type_map, + &wasm_ref_type, false, error_buf, + error_buf_size)) { goto fail; } type = wasm_ref_type.ref_type; @@ -12078,8 +12303,8 @@ re_scan: #else read_leb_int32(p, p_end, heap_type); if (heap_type >= 0) { - if (!check_type_index(module, heap_type, error_buf, - error_buf_size)) { + if (!check_type_index(module, module->type_count, heap_type, + error_buf, error_buf_size)) { goto fail; } wasm_set_refheaptype_typeidx(&wasm_ref_type.ref_ht_typeidx, @@ -12256,7 +12481,7 @@ re_scan: if (opcode == WASM_OP_BR_ON_NULL) { if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, false, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) { goto fail; } @@ -12303,7 +12528,7 @@ re_scan: PUSH_REF(type); } if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, false, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) { goto fail; } @@ -12728,8 +12953,8 @@ re_scan: } #endif CHECK_MEMORY(); - read_leb_uint32(p, p_end, align); /* align */ - read_leb_uint32(p, p_end, mem_offset); /* offset */ + read_leb_uint32(p, p_end, align); /* align */ + read_leb_mem_offset(p, p_end, mem_offset); /* offset */ if (!check_memory_access_align(opcode, align, error_buf, error_buf_size)) { goto fail; @@ -12747,7 +12972,7 @@ re_scan: case WASM_OP_I32_LOAD8_U: case WASM_OP_I32_LOAD16_S: case WASM_OP_I32_LOAD16_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I32); break; case WASM_OP_I64_LOAD: case WASM_OP_I64_LOAD8_S: @@ -12756,35 +12981,35 @@ re_scan: case WASM_OP_I64_LOAD16_U: case WASM_OP_I64_LOAD32_S: case WASM_OP_I64_LOAD32_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I64); break; case WASM_OP_F32_LOAD: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_F32); break; case WASM_OP_F64_LOAD: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_F64); break; /* store */ case WASM_OP_I32_STORE: case WASM_OP_I32_STORE8: case WASM_OP_I32_STORE16: POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_I64_STORE: case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_F32_STORE: POP_F32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_F64_STORE: POP_F64(); - POP_I32(); + POP_MEM_OFFSET(); break; default: break; @@ -12800,7 +13025,7 @@ re_scan: "zero byte expected"); goto fail; } - PUSH_I32(); + PUSH_PAGE_COUNT(); module->possible_memory_grow = true; #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 @@ -12816,7 +13041,7 @@ re_scan: "zero byte expected"); goto fail; } - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, mem_offset_type); module->possible_memory_grow = true; #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ @@ -12863,6 +13088,7 @@ re_scan: break; case WASM_OP_F32_CONST: + CHECK_BUF(p, p_end, sizeof(float32)); p += sizeof(float32); #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); @@ -12881,6 +13107,7 @@ re_scan: break; case WASM_OP_F64_CONST: + CHECK_BUF(p, p_end, sizeof(float64)); p += sizeof(float64); #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); @@ -13141,7 +13368,8 @@ re_scan: #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, type_idx); #endif - if (!check_type_index(module, type_idx, error_buf, + if (!check_type_index(module, module->type_count, + type_idx, error_buf, error_buf_size)) { goto fail; } @@ -13227,7 +13455,8 @@ re_scan: #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, type_idx); #endif - if (!check_type_index(module, type_idx, error_buf, + if (!check_type_index(module, module->type_count, + type_idx, error_buf, error_buf_size)) { goto fail; } @@ -13640,7 +13869,8 @@ re_scan: emit_uint32(loader_ctx, (uint32)heap_type); #endif if (heap_type >= 0) { - if (!check_type_index(module, heap_type, error_buf, + if (!check_type_index(module, module->type_count, + heap_type, error_buf, error_buf_size)) { goto fail; } @@ -13785,7 +14015,7 @@ re_scan: } PUSH_REF(type_tmp); if (!(frame_csp_tmp = check_branch_block( - loader_ctx, &p, p_end, false, error_buf, + loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) { goto fail; } @@ -14177,7 +14407,7 @@ re_scan: POP_I32(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -14211,6 +14441,7 @@ re_scan: } case WASM_OP_MEMORY_COPY: { + CHECK_BUF(p, p_end, sizeof(int16)); /* both src and dst memory index should be 0 */ if (*(int16 *)p != 0x0000) goto fail_zero_byte_expected; @@ -14220,9 +14451,9 @@ re_scan: && module->memory_count == 0) goto fail_unknown_memory; - POP_I32(); - POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); + POP_MEM_OFFSET(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -14240,10 +14471,9 @@ re_scan: && module->memory_count == 0) { goto fail_unknown_memory; } - - POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); POP_I32(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -14489,6 +14719,7 @@ re_scan: #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) case WASM_OP_SIMD_PREFIX: { + /* TODO: memory64 offset type changes */ uint32 opcode1; #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -14984,13 +15215,6 @@ re_scan: break; } - case SIMD_i32x4_narrow_i64x2_s: - case SIMD_i32x4_narrow_i64x2_u: - { - POP2_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); - break; - } - case SIMD_i32x4_extend_low_i16x8_s: case SIMD_i32x4_extend_high_i16x8_s: case SIMD_i32x4_extend_low_i16x8_u: @@ -15017,7 +15241,6 @@ re_scan: case SIMD_i32x4_max_s: case SIMD_i32x4_max_u: case SIMD_i32x4_dot_i16x8_s: - case SIMD_i32x4_avgr_u: case SIMD_i32x4_extmul_low_i16x8_s: case SIMD_i32x4_extmul_high_i16x8_s: case SIMD_i32x4_extmul_low_i16x8_u: @@ -15081,7 +15304,6 @@ re_scan: /* f32x4 operation */ case SIMD_f32x4_abs: case SIMD_f32x4_neg: - case SIMD_f32x4_round: case SIMD_f32x4_sqrt: { POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); @@ -15104,7 +15326,6 @@ re_scan: /* f64x2 operation */ case SIMD_f64x2_abs: case SIMD_f64x2_neg: - case SIMD_f64x2_round: case SIMD_f64x2_sqrt: { POP_AND_PUSH(VALUE_TYPE_V128, VALUE_TYPE_V128); @@ -15165,8 +15386,8 @@ re_scan: #endif if (opcode1 != WASM_OP_ATOMIC_FENCE) { CHECK_MEMORY(); - read_leb_uint32(p, p_end, align); /* align */ - read_leb_uint32(p, p_end, mem_offset); /* offset */ + read_leb_uint32(p, p_end, align); /* align */ + read_leb_mem_offset(p, p_end, mem_offset); /* offset */ if (!check_memory_align_equal(opcode1, align, error_buf, error_buf_size)) { goto fail; @@ -15180,18 +15401,20 @@ re_scan: #endif switch (opcode1) { case WASM_OP_ATOMIC_NOTIFY: - POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_I32(); + POP_MEM_OFFSET(); + PUSH_I32(); break; case WASM_OP_ATOMIC_WAIT32: POP_I64(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_WAIT64: POP_I64(); POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_FENCE: @@ -15205,26 +15428,26 @@ re_scan: case WASM_OP_ATOMIC_I32_LOAD: case WASM_OP_ATOMIC_I32_LOAD8_U: case WASM_OP_ATOMIC_I32_LOAD16_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I32); break; case WASM_OP_ATOMIC_I32_STORE: case WASM_OP_ATOMIC_I32_STORE8: case WASM_OP_ATOMIC_I32_STORE16: POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_ATOMIC_I64_LOAD: case WASM_OP_ATOMIC_I64_LOAD8_U: case WASM_OP_ATOMIC_I64_LOAD16_U: case WASM_OP_ATOMIC_I64_LOAD32_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I64); break; case WASM_OP_ATOMIC_I64_STORE: case WASM_OP_ATOMIC_I64_STORE8: case WASM_OP_ATOMIC_I64_STORE16: case WASM_OP_ATOMIC_I64_STORE32: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_ATOMIC_RMW_I32_ADD: case WASM_OP_ATOMIC_RMW_I32_ADD8_U: @@ -15244,7 +15467,9 @@ re_scan: case WASM_OP_ATOMIC_RMW_I32_XCHG: case WASM_OP_ATOMIC_RMW_I32_XCHG8_U: case WASM_OP_ATOMIC_RMW_I32_XCHG16_U: - POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_I32(); + POP_MEM_OFFSET(); + PUSH_I32(); break; case WASM_OP_ATOMIC_RMW_I64_ADD: case WASM_OP_ATOMIC_RMW_I64_ADD8_U: @@ -15271,7 +15496,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I64_XCHG16_U: case WASM_OP_ATOMIC_RMW_I64_XCHG32_U: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I64(); break; case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: @@ -15279,7 +15504,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: POP_I32(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: @@ -15288,7 +15513,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: POP_I64(); POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I64(); break; default: diff --git a/core/iwasm/interpreter/wasm_loader.h b/core/iwasm/interpreter/wasm_loader.h index 8b0dc77d6..676770ee2 100644 --- a/core/iwasm/interpreter/wasm_loader.h +++ b/core/iwasm/interpreter/wasm_loader.h @@ -28,7 +28,7 @@ wasm_loader_load(uint8 *buf, uint32 size, #if WASM_ENABLE_MULTI_MODULE != 0 bool main_module, #endif - char *error_buf, uint32 error_buf_size); + const LoadArgs *args, char *error_buf, uint32 error_buf_size); /** * Load a WASM module from a specified WASM section list. diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 7d37006a8..3deec511f 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -47,6 +47,7 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) #define skip_leb_int64(p, p_end) skip_leb(p) #define skip_leb_uint32(p, p_end) skip_leb(p) #define skip_leb_int32(p, p_end) skip_leb(p) +#define skip_leb_mem_offset(p, p_end) skip_leb(p) static bool is_32bit_type(uint8 type) @@ -116,7 +117,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, } else if (sign && maxbits == 32) { if (shift < maxbits) { - /* Sign extend, second highest bit is the sign bit */ + /* Sign extend, second-highest bit is the sign bit */ if ((uint8)byte & 0x40) result |= (~((uint64)0)) << shift; } @@ -132,7 +133,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, } else if (sign && maxbits == 64) { if (shift < maxbits) { - /* Sign extend, second highest bit is the sign bit */ + /* Sign extend, second-highest bit is the sign bit */ if ((uint8)byte & 0x40) result |= (~((uint64)0)) << shift; } @@ -180,6 +181,18 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, res = (int32)res64; \ } while (0) +#if WASM_ENABLE_MEMORY64 != 0 +#define read_leb_mem_offset(p, p_end, res) \ + do { \ + uint64 res64; \ + read_leb((uint8 **)&p, p_end, is_memory64 ? 64 : 32, false, &res64, \ + error_buf, error_buf_size); \ + res = (mem_offset_t)res64; \ + } while (0) +#else +#define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res) +#endif + static void * loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) { @@ -683,6 +696,38 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, return true; } +static bool +check_memory_flag(const uint8 mem_flag) +{ + /* Check whether certain features indicated by mem_flag are enabled in + * runtime */ + if (mem_flag > MAX_PAGE_COUNT_FLAG) { +#if WASM_ENABLE_SHARED_MEMORY == 0 + if (mem_flag & SHARED_MEMORY_FLAG) { + LOG_VERBOSE("shared memory flag was found, please enable shared " + "memory, lib-pthread or lib-wasi-threads"); + return false; + } +#endif +#if WASM_ENABLE_MEMORY64 == 0 + if (mem_flag & MEMORY64_FLAG) { + LOG_VERBOSE("memory64 flag was found, please enable memory64"); + return false; + } +#endif + } + + if (mem_flag > MAX_PAGE_COUNT_FLAG + SHARED_MEMORY_FLAG + MEMORY64_FLAG) { + return false; + } + else if ((mem_flag & SHARED_MEMORY_FLAG) + && !(mem_flag & MAX_PAGE_COUNT_FLAG)) { + return false; + } + + return true; +} + static bool load_memory_import(const uint8 **p_buf, const uint8 *buf_end, WASMModule *parent_module, const char *sub_module_name, @@ -695,20 +740,28 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT / DEFAULT_NUM_BYTES_PER_PAGE; #else - uint32 max_page_count = DEFAULT_MAX_PAGES; + uint32 max_page_count; #endif /* WASM_ENABLE_APP_FRAMEWORK */ - uint32 declare_max_page_count_flag = 0; + uint32 mem_flag = 0; + bool is_memory64 = false; uint32 declare_init_page_count = 0; uint32 declare_max_page_count = 0; - read_leb_uint32(p, p_end, declare_max_page_count_flag); - read_leb_uint32(p, p_end, declare_init_page_count); - bh_assert(declare_init_page_count <= 65536); + read_leb_uint32(p, p_end, mem_flag); + bh_assert(check_memory_flag(mem_flag)); - if (declare_max_page_count_flag & 1) { +#if WASM_ENABLE_APP_FRAMEWORK == 0 + is_memory64 = mem_flag & MEMORY64_FLAG; + max_page_count = is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; +#endif + + read_leb_uint32(p, p_end, declare_init_page_count); + bh_assert(declare_init_page_count <= max_page_count); + + if (mem_flag & MAX_PAGE_COUNT_FLAG) { read_leb_uint32(p, p_end, declare_max_page_count); bh_assert(declare_init_page_count <= declare_max_page_count); - bh_assert(declare_max_page_count <= 65536); + bh_assert(declare_max_page_count <= max_page_count); if (declare_max_page_count > max_page_count) { declare_max_page_count = max_page_count; } @@ -719,12 +772,13 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, } /* now we believe all declaration are ok */ - memory->flags = declare_max_page_count_flag; + memory->flags = mem_flag; memory->init_page_count = declare_init_page_count; memory->max_page_count = declare_max_page_count; memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; + (void)check_memory_flag; return true; } @@ -811,26 +865,28 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT / DEFAULT_NUM_BYTES_PER_PAGE; #else - uint32 max_page_count = DEFAULT_MAX_PAGES; + uint32 max_page_count; + bool is_memory64 = false; #endif p_org = p; read_leb_uint32(p, p_end, memory->flags); bh_assert(p - p_org <= 1); (void)p_org; -#if WASM_ENABLE_SHARED_MEMORY == 0 - bh_assert(memory->flags <= 1); -#else - bh_assert(memory->flags <= 3 && memory->flags != 2); + bh_assert(check_memory_flag(memory->flags)); + +#if WASM_ENABLE_APP_FRAMEWORK == 0 + is_memory64 = memory->flags & MEMORY64_FLAG; + max_page_count = is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; #endif read_leb_uint32(p, p_end, memory->init_page_count); - bh_assert(memory->init_page_count <= 65536); + bh_assert(memory->init_page_count <= max_page_count); if (memory->flags & 1) { read_leb_uint32(p, p_end, memory->max_page_count); bh_assert(memory->init_page_count <= memory->max_page_count); - bh_assert(memory->max_page_count <= 65536); + bh_assert(memory->max_page_count <= max_page_count); if (memory->max_page_count > max_page_count) memory->max_page_count = max_page_count; } @@ -842,6 +898,7 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; + (void)check_memory_flag; return true; } @@ -1704,6 +1761,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, bool is_passive = false; uint32 mem_flag; #endif + uint8 mem_offset_type; read_leb_uint32(p, p_end, data_seg_count); @@ -1750,11 +1808,35 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, < module->import_memory_count + module->memory_count); #endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_BULK_MEMORY != 0 + if (!is_passive) +#endif /* WASM_ENABLE_BULK_MEMORY */ + { +#if WASM_ENABLE_MEMORY64 != 0 + /* 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.memory.flags; + } + else { + memory_flag = + module + ->memories[mem_index - module->import_memory_count] + .flags; + } + mem_offset_type = memory_flag & MEMORY64_FLAG ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#else + mem_offset_type = VALUE_TYPE_I32; +#endif /* WASM_ENABLE_MEMORY64 */ + } + #if WASM_ENABLE_BULK_MEMORY != 0 if (!is_passive) #endif if (!load_init_expr(module, &p, p_end, &init_expr, - VALUE_TYPE_I32, error_buf, error_buf_size)) + mem_offset_type, error_buf, error_buf_size)) return false; read_leb_uint32(p, p_end, data_seg_len); @@ -2485,8 +2567,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, *buf_func = NULL, *buf_func_end = NULL; WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL; WASMGlobal *aux_stack_top_global = NULL, *global; - uint64 aux_data_end = (uint64)-1, aux_heap_base = (uint64)-1, - aux_stack_top = (uint64)-1; + uint64 aux_data_end = (uint64)-1LL, aux_heap_base = (uint64)-1LL, + aux_stack_top = (uint64)-1LL; uint32 global_index, func_index, i; uint32 aux_data_end_global_index = (uint32)-1; uint32 aux_heap_base_global_index = (uint32)-1; @@ -2607,7 +2689,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, aux_heap_base_global = global; aux_heap_base = (uint64)(uint32)global->init_expr.u.i32; aux_heap_base_global_index = export->index; - LOG_VERBOSE("Found aux __heap_base global, value: %d", + LOG_VERBOSE("Found aux __heap_base global, value: %" PRIu64, aux_heap_base); } } @@ -2620,7 +2702,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, aux_data_end_global = global; aux_data_end = (uint64)(uint32)global->init_expr.u.i32; aux_data_end_global_index = export->index; - LOG_VERBOSE("Found aux __data_end global, value: %d", + LOG_VERBOSE("Found aux __data_end global, value: %" PRIu64, aux_data_end); aux_data_end = align_uint64(aux_data_end, 16); } @@ -2669,10 +2751,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, aux_stack_top > aux_data_end ? (uint32)(aux_stack_top - aux_data_end) : (uint32)aux_stack_top; - LOG_VERBOSE("Found aux stack top global, value: %d, " - "global index: %d, stack size: %d", - aux_stack_top, global_index, - module->aux_stack_size); + LOG_VERBOSE( + "Found aux stack top global, value: %" PRIu64 ", " + "global index: %d, stack size: %d", + aux_stack_top, global_index, + module->aux_stack_size); break; } } @@ -2819,7 +2902,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, /* Reset memory info to decrease memory usage */ memory_import->num_bytes_per_page = shrunk_memory_size; memory_import->init_page_count = 1; - LOG_VERBOSE("Shrink import memory size to %d", + LOG_VERBOSE("Shrink import memory size to %" PRIu64, shrunk_memory_size); } } @@ -2832,7 +2915,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, /* Reset memory info to decrease memory usage */ memory->num_bytes_per_page = shrunk_memory_size; memory->init_page_count = 1; - LOG_VERBOSE("Shrink memory size to %d", + LOG_VERBOSE("Shrink memory size to %" PRIu64, shrunk_memory_size); } } @@ -2911,7 +2994,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, } static WASMModule * -create_module(char *error_buf, uint32 error_buf_size) +create_module(char *name, char *error_buf, uint32 error_buf_size) { WASMModule *module = loader_malloc(sizeof(WASMModule), error_buf, error_buf_size); @@ -2926,7 +3009,7 @@ create_module(char *error_buf, uint32 error_buf_size) /* Set start_function to -1, means no start function */ module->start_function = (uint32)-1; - module->name = ""; + module->name = name; #if WASM_ENABLE_FAST_INTERP == 0 module->br_table_cache_list = &module->br_table_cache_list_head; @@ -2952,7 +3035,7 @@ WASMModule * wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf, uint32 error_buf_size) { - WASMModule *module = create_module(error_buf, error_buf_size); + WASMModule *module = create_module("", error_buf, error_buf_size); if (!module) return NULL; @@ -3123,10 +3206,10 @@ load(const uint8 *buf, uint32 size, WASMModule *module, char *error_buf, } WASMModule * -wasm_loader_load(uint8 *buf, uint32 size, char *error_buf, +wasm_loader_load(uint8 *buf, uint32 size, const LoadArgs *args, char *error_buf, uint32 error_buf_size) { - WASMModule *module = create_module(error_buf, error_buf_size); + WASMModule *module = create_module(args->name, error_buf, error_buf_size); if (!module) { return NULL; } @@ -3532,8 +3615,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: - skip_leb_uint32(p, p_end); /* align */ - skip_leb_uint32(p, p_end); /* offset */ + skip_leb_uint32(p, p_end); /* align */ + skip_leb_mem_offset(p, p_end); /* offset */ break; case WASM_OP_MEMORY_SIZE: @@ -3748,6 +3831,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, #if WASM_ENABLE_SHARED_MEMORY != 0 case WASM_OP_ATOMIC_PREFIX: { + /* TODO: memory64 offset type changes */ uint32 opcode1; /* atomic_op (u32_leb) + memarg (2 u32_leb) */ @@ -3757,8 +3841,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, opcode = (uint8)opcode1; if (opcode != WASM_OP_ATOMIC_FENCE) { - skip_leb_uint32(p, p_end); /* align */ - skip_leb_uint32(p, p_end); /* offset */ + skip_leb_uint32(p, p_end); /* align */ + skip_leb_mem_offset(p, p_end); /* offset */ } else { /* atomic.fence doesn't have memarg */ @@ -4260,11 +4344,11 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf, wasm_loader_emit_ptr(loader_ctx, NULL); \ } while (0) -#define emit_br_info(frame_csp) \ - do { \ - if (!wasm_loader_emit_br_info(loader_ctx, frame_csp, error_buf, \ - error_buf_size)) \ - goto fail; \ +#define emit_br_info(frame_csp, is_br) \ + do { \ + if (!wasm_loader_emit_br_info(loader_ctx, frame_csp, is_br, error_buf, \ + error_buf_size)) \ + goto fail; \ } while (0) #define LAST_OP_OUTPUT_I32() \ @@ -4649,7 +4733,7 @@ apply_label_patch(WASMLoaderContext *ctx, uint8 depth, uint8 patch_type) static bool wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, - char *error_buf, uint32 error_buf_size) + bool is_br, char *error_buf, uint32 error_buf_size) { /* br info layout: * a) arity of target block @@ -4698,6 +4782,8 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, /* Part e */ dynamic_offset = frame_csp->dynamic_offset + wasm_get_cell_num(types, arity); + if (is_br) + ctx->dynamic_offset = dynamic_offset; for (i = (int32)arity - 1; i >= 0; i--) { cell = (uint8)wasm_value_type_cell_num(types[i]); dynamic_offset -= cell; @@ -5073,6 +5159,11 @@ fail: goto fail; \ } while (0) +#define PUSH_MEM_OFFSET() PUSH_OFFSET_TYPE(mem_offset_type) +#define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() + +#define POP_MEM_OFFSET() POP_OFFSET_TYPE(mem_offset_type) + #define POP_AND_PUSH(type_pop, type_push) \ do { \ if (!(wasm_loader_push_pop_frame_ref_offset( \ @@ -5127,6 +5218,15 @@ fail: goto fail; \ } while (0) +#define PUSH_MEM_OFFSET() \ + do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, mem_offset_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() + #define POP_I32() \ do { \ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, error_buf, \ @@ -5162,6 +5262,13 @@ fail: goto fail; \ } while (0) +#define POP_MEM_OFFSET() \ + do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, mem_offset_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, \ @@ -5382,8 +5489,8 @@ fail: } while (0) static bool -wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, - bool is_br_table, char *error_buf, uint32 error_buf_size) +wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, uint8 opcode, + char *error_buf, uint32 error_buf_size) { BranchBlock *target_block, *cur_block; BlockType *target_block_type; @@ -5441,7 +5548,7 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, /* Backup stack data since it may be changed in the below push operations, and the stack data may be used when checking other target blocks of opcode br_table */ - if (is_br_table) { + if (opcode == WASM_OP_BR_TABLE) { uint64 total_size; frame_ref_after_popped = loader_ctx->frame_ref; @@ -5479,13 +5586,13 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, } #if WASM_ENABLE_FAST_INTERP != 0 - emit_br_info(target_block); + emit_br_info(target_block, opcode == WASM_OP_BR); #endif /* Restore the stack data, note that frame_ref_bottom, frame_reftype_map_bottom, frame_offset_bottom may be re-allocated in the above push operations */ - if (is_br_table) { + if (opcode == WASM_OP_BR_TABLE) { uint32 total_size; /* The stack operand num should not be smaller than before @@ -5529,7 +5636,7 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth, } #if WASM_ENABLE_FAST_INTERP != 0 - emit_br_info(target_block); + emit_br_info(target_block, opcode == WASM_OP_BR); #endif ret = true; @@ -5540,7 +5647,7 @@ fail: wasm_runtime_free(frame_ref_buf); #if WASM_ENABLE_FAST_INTERP != 0 if (frame_offset_buf && frame_offset_buf != frame_offset_tmp) - wasm_runtime_free(frame_offset_tmp); + wasm_runtime_free(frame_offset_buf); #endif return ret; @@ -5548,14 +5655,14 @@ fail: static BranchBlock * check_branch_block(WASMLoaderContext *loader_ctx, uint8 **p_buf, uint8 *buf_end, - bool is_br_table, char *error_buf, uint32 error_buf_size) + uint8 opcode, char *error_buf, uint32 error_buf_size) { uint8 *p = *p_buf, *p_end = buf_end; BranchBlock *frame_csp_tmp; uint32 depth; read_leb_uint32(p, p_end, depth); - if (!wasm_loader_check_br(loader_ctx, depth, is_br_table, error_buf, + if (!wasm_loader_check_br(loader_ctx, depth, opcode, error_buf, error_buf_size)) { goto fail; } @@ -5772,10 +5879,11 @@ 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; + uint8 *param_types, *local_types, local_type, global_type, mem_offset_type; BlockType func_block_type; uint16 *local_offsets, local_offset; - uint32 count, local_idx, global_idx, u32, align, mem_offset, i; + uint32 count, local_idx, global_idx, u32, align, i; + mem_offset_t mem_offset; int32 i32, i32_const = 0; int64 i64_const; uint8 opcode, u8; @@ -5797,6 +5905,19 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, LOG_OP("\nProcessing func | [%d] params | [%d] locals | [%d] return\n", func->param_cell_num, func->local_cell_num, func->ret_cell_num); #endif +#if WASM_ENABLE_MEMORY64 != 0 + bool is_memory64 = false; + /* TODO: multi-memories for now assuming the memory idx type is consistent + * across multi-memories */ + if (module->import_memory_count > 0) + is_memory64 = module->import_memories[0].u.memory.flags & MEMORY64_FLAG; + else if (module->memory_count > 0) + is_memory64 = module->memories[0].flags & MEMORY64_FLAG; + + mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32; +#else + mem_offset_type = VALUE_TYPE_I32; +#endif global_count = module->import_global_count + module->global_count; @@ -6105,8 +6226,8 @@ re_scan: bh_memcpy_s(loader_ctx->frame_offset, size, block->param_frame_offsets, size); loader_ctx->frame_offset += (size / sizeof(int16)); - loader_ctx->dynamic_offset = block->start_dynamic_offset; } + loader_ctx->dynamic_offset = block->start_dynamic_offset; #endif break; @@ -6179,7 +6300,7 @@ re_scan: case WASM_OP_BR: { if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, false, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) goto fail; @@ -6193,7 +6314,7 @@ re_scan: POP_I32(); if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, false, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) goto fail; @@ -6223,7 +6344,7 @@ re_scan: #endif for (i = 0; i <= count; i++) { if (!(frame_csp_tmp = - check_branch_block(loader_ctx, &p, p_end, true, + check_branch_block(loader_ctx, &p, p_end, opcode, error_buf, error_buf_size))) goto fail; @@ -7105,8 +7226,8 @@ re_scan: } #endif CHECK_MEMORY(); - read_leb_uint32(p, p_end, align); /* align */ - read_leb_uint32(p, p_end, mem_offset); /* offset */ + read_leb_uint32(p, p_end, align); /* align */ + read_leb_mem_offset(p, p_end, mem_offset); /* offset */ #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, mem_offset); #endif @@ -7120,7 +7241,7 @@ re_scan: case WASM_OP_I32_LOAD8_U: case WASM_OP_I32_LOAD16_S: case WASM_OP_I32_LOAD16_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I32); break; case WASM_OP_I64_LOAD: case WASM_OP_I64_LOAD8_S: @@ -7129,35 +7250,35 @@ re_scan: case WASM_OP_I64_LOAD16_U: case WASM_OP_I64_LOAD32_S: case WASM_OP_I64_LOAD32_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I64); break; case WASM_OP_F32_LOAD: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_F32); break; case WASM_OP_F64_LOAD: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_F64); break; /* store */ case WASM_OP_I32_STORE: case WASM_OP_I32_STORE8: case WASM_OP_I32_STORE16: POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_I64_STORE: case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_F32_STORE: POP_F32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_F64_STORE: POP_F64(); - POP_I32(); + POP_MEM_OFFSET(); break; default: break; @@ -7170,7 +7291,7 @@ re_scan: /* reserved byte 0x00 */ bh_assert(*p == 0x00); p++; - PUSH_I32(); + PUSH_PAGE_COUNT(); module->possible_memory_grow = true; #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 @@ -7183,7 +7304,7 @@ re_scan: /* reserved byte 0x00 */ bh_assert(*p == 0x00); p++; - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, mem_offset_type); module->possible_memory_grow = true; #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ @@ -7230,6 +7351,7 @@ re_scan: break; case WASM_OP_F32_CONST: + CHECK_BUF(p, p_end, sizeof(float32)); p += sizeof(float32); #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); @@ -7248,6 +7370,7 @@ re_scan: break; case WASM_OP_F64_CONST: + CHECK_BUF(p, p_end, sizeof(float64)); p += sizeof(float64); #if WASM_ENABLE_FAST_INTERP != 0 skip_label(); @@ -7534,7 +7657,7 @@ re_scan: POP_I32(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -7555,6 +7678,7 @@ re_scan: } case WASM_OP_MEMORY_COPY: { + CHECK_BUF(p, p_end, sizeof(int16)); /* both src and dst memory index should be 0 */ bh_assert(*(int16 *)p == 0x0000); p += 2; @@ -7563,9 +7687,9 @@ re_scan: + module->memory_count > 0); - POP_I32(); - POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); + POP_MEM_OFFSET(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -7580,9 +7704,9 @@ re_scan: + module->memory_count > 0); + POP_MEM_OFFSET(); POP_I32(); - POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -7746,8 +7870,8 @@ re_scan: #endif if (opcode1 != WASM_OP_ATOMIC_FENCE) { CHECK_MEMORY(); - read_leb_uint32(p, p_end, align); /* align */ - read_leb_uint32(p, p_end, mem_offset); /* offset */ + read_leb_uint32(p, p_end, align); /* align */ + read_leb_mem_offset(p, p_end, mem_offset); /* offset */ #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, mem_offset); #endif @@ -7757,18 +7881,20 @@ re_scan: #endif switch (opcode1) { case WASM_OP_ATOMIC_NOTIFY: - POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_I32(); + POP_MEM_OFFSET(); + PUSH_I32(); break; case WASM_OP_ATOMIC_WAIT32: POP_I64(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_WAIT64: POP_I64(); POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_FENCE: @@ -7779,26 +7905,26 @@ re_scan: case WASM_OP_ATOMIC_I32_LOAD: case WASM_OP_ATOMIC_I32_LOAD8_U: case WASM_OP_ATOMIC_I32_LOAD16_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I32); break; case WASM_OP_ATOMIC_I32_STORE: case WASM_OP_ATOMIC_I32_STORE8: case WASM_OP_ATOMIC_I32_STORE16: POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_ATOMIC_I64_LOAD: case WASM_OP_ATOMIC_I64_LOAD8_U: case WASM_OP_ATOMIC_I64_LOAD16_U: case WASM_OP_ATOMIC_I64_LOAD32_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I64); break; case WASM_OP_ATOMIC_I64_STORE: case WASM_OP_ATOMIC_I64_STORE8: case WASM_OP_ATOMIC_I64_STORE16: case WASM_OP_ATOMIC_I64_STORE32: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_ATOMIC_RMW_I32_ADD: case WASM_OP_ATOMIC_RMW_I32_ADD8_U: @@ -7818,7 +7944,9 @@ re_scan: case WASM_OP_ATOMIC_RMW_I32_XCHG: case WASM_OP_ATOMIC_RMW_I32_XCHG8_U: case WASM_OP_ATOMIC_RMW_I32_XCHG16_U: - POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_I32(); + POP_MEM_OFFSET(); + PUSH_I32(); break; case WASM_OP_ATOMIC_RMW_I64_ADD: case WASM_OP_ATOMIC_RMW_I64_ADD8_U: @@ -7845,7 +7973,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I64_XCHG16_U: case WASM_OP_ATOMIC_RMW_I64_XCHG32_U: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I64(); break; case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: @@ -7853,7 +7981,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: POP_I32(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: @@ -7862,7 +7990,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: POP_I64(); POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I64(); break; default: diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index 98e5b1325..db5e5e40b 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -593,8 +593,8 @@ typedef enum WASMSimdEXTOpcode { /* placeholder = 0xa2 */ SIMD_i32x4_all_true = 0xa3, SIMD_i32x4_bitmask = 0xa4, - SIMD_i32x4_narrow_i64x2_s = 0xa5, - SIMD_i32x4_narrow_i64x2_u = 0xa6, + /* placeholder = 0xa5 */ + /* placeholder = 0xa6 */ SIMD_i32x4_extend_low_i16x8_s = 0xa7, SIMD_i32x4_extend_high_i16x8_s = 0xa8, SIMD_i32x4_extend_low_i16x8_u = 0xa9, @@ -603,19 +603,19 @@ typedef enum WASMSimdEXTOpcode { SIMD_i32x4_shr_s = 0xac, SIMD_i32x4_shr_u = 0xad, SIMD_i32x4_add = 0xae, - SIMD_i32x4_add_sat_s = 0xaf, - SIMD_i32x4_add_sat_u = 0xb0, + /* placeholder = 0xaf */ + /* placeholder = 0xb0 */ SIMD_i32x4_sub = 0xb1, - SIMD_i32x4_sub_sat_s = 0xb2, - SIMD_i32x4_sub_sat_u = 0xb3, - /* placeholder = 0xb4 */ + /* placeholder = 0xb2 */ + /* placeholder = 0xb3 */ + /* placeholder = 0xb4 */ SIMD_i32x4_mul = 0xb5, SIMD_i32x4_min_s = 0xb6, SIMD_i32x4_min_u = 0xb7, SIMD_i32x4_max_s = 0xb8, SIMD_i32x4_max_u = 0xb9, SIMD_i32x4_dot_i16x8_s = 0xba, - SIMD_i32x4_avgr_u = 0xbb, + /* placeholder = 0xbb */ SIMD_i32x4_extmul_low_i16x8_s = 0xbc, SIMD_i32x4_extmul_high_i16x8_s = 0xbd, SIMD_i32x4_extmul_low_i16x8_u = 0xbe, @@ -658,7 +658,7 @@ typedef enum WASMSimdEXTOpcode { /* f32x4 operation */ SIMD_f32x4_abs = 0xe0, SIMD_f32x4_neg = 0xe1, - SIMD_f32x4_round = 0xe2, + /* placeholder = 0xe2 */ SIMD_f32x4_sqrt = 0xe3, SIMD_f32x4_add = 0xe4, SIMD_f32x4_sub = 0xe5, @@ -672,7 +672,7 @@ typedef enum WASMSimdEXTOpcode { /* f64x2 operation */ SIMD_f64x2_abs = 0xec, SIMD_f64x2_neg = 0xed, - SIMD_f64x2_round = 0xee, + /* placeholder = 0xee */ SIMD_f64x2_sqrt = 0xef, SIMD_f64x2_add = 0xf0, SIMD_f64x2_sub = 0xf1, diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f80d182df..cb5e384fa 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -60,13 +60,13 @@ wasm_load(uint8 *buf, uint32 size, #if WASM_ENABLE_MULTI_MODULE != 0 bool main_module, #endif - char *error_buf, uint32 error_buf_size) + const LoadArgs *name, char *error_buf, uint32 error_buf_size) { return wasm_loader_load(buf, size, #if WASM_ENABLE_MULTI_MODULE != 0 main_module, #endif - error_buf, error_buf_size); + name, error_buf, error_buf_size); } WASMModule * @@ -162,7 +162,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, char *error_buf, uint32 error_buf_size) { WASMModule *module = module_inst->module; - uint32 inc_page_count, global_idx; + uint32 inc_page_count, global_idx, default_max_page; uint32 bytes_of_last_page, bytes_to_page_end; uint64 aux_heap_base, heap_offset = (uint64)num_bytes_per_page * init_page_count; @@ -171,7 +171,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, bool is_shared_memory = false; #if WASM_ENABLE_SHARED_MEMORY != 0 - is_shared_memory = flags & 0x02 ? true : false; + is_shared_memory = flags & SHARED_MEMORY_FLAG ? true : false; /* shared memory */ if (is_shared_memory && parent != NULL) { @@ -186,6 +186,14 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, (void)flags; #endif /* end of WASM_ENABLE_SHARED_MEMORY */ +#if WASM_ENABLE_MEMORY64 != 0 + if (flags & MEMORY64_FLAG) { + memory->is_memory64 = 1; + } +#endif + default_max_page = + memory->is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; + if (heap_size > 0 && module_inst->module->malloc_function != (uint32)-1 && module_inst->module->free_function != (uint32)-1) { /* Disable app heap, use malloc/free function exported @@ -195,7 +203,8 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, /* If initial memory is the largest size allowed, disallowing insert host * managed heap */ - if (heap_size > 0 && heap_offset == MAX_LINEAR_MEMORY_SIZE) { + if (heap_size > 0 + && heap_offset == GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)) { set_error_buf(error_buf, error_buf_size, "failed to insert app heap into linear memory, " "try using `--heap-size=0` option"); @@ -253,8 +262,18 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, && global_idx < module_inst->e->global_count); global_addr = module_inst->global_data + module_inst->e->globals[global_idx].data_offset; - *(uint32 *)global_addr = (uint32)aux_heap_base; - LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base); +#if WASM_ENABLE_MEMORY64 != 0 + if (memory->is_memory64) { + /* For memory64, the global value should be i64 */ + *(uint64 *)global_addr = aux_heap_base; + } + else +#endif + { + /* For memory32, the global value should be i32 */ + *(uint32 *)global_addr = (uint32)aux_heap_base; + } + LOG_VERBOSE("Reset __heap_base global to %" PRIu64, aux_heap_base); } else { /* Insert app heap before new page */ @@ -267,30 +286,34 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, } init_page_count += inc_page_count; max_page_count += inc_page_count; - if (init_page_count > DEFAULT_MAX_PAGES) { + if (init_page_count > default_max_page) { set_error_buf(error_buf, error_buf_size, "failed to insert app heap into linear memory, " "try using `--heap-size=0` option"); return NULL; } - if (max_page_count > DEFAULT_MAX_PAGES) - max_page_count = DEFAULT_MAX_PAGES; + + if (max_page_count > default_max_page) + max_page_count = default_max_page; } LOG_VERBOSE("Memory instantiate:"); LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u", num_bytes_per_page, init_page_count, max_page_count); - LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); + LOG_VERBOSE(" heap offset: %" PRIu64 ", heap size: %u\n", heap_offset, + heap_size); max_memory_data_size = (uint64)num_bytes_per_page * max_page_count; - bh_assert(max_memory_data_size <= MAX_LINEAR_MEMORY_SIZE); + bh_assert(max_memory_data_size + <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)); (void)max_memory_data_size; bh_assert(memory != NULL); if (wasm_allocate_linear_memory(&memory->memory_data, is_shared_memory, - num_bytes_per_page, init_page_count, - max_page_count, &memory_data_size) + memory->is_memory64, num_bytes_per_page, + init_page_count, max_page_count, + &memory_data_size) != BHT_OK) { set_error_buf(error_buf, error_buf_size, "allocate linear memory failed"); @@ -1947,7 +1970,8 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, WASMGlobalInstance *globals = NULL, *global; WASMTableInstance *first_table; uint32 global_count, i; - uint32 base_offset, length, extra_info_offset; + uint32 length, extra_info_offset; + mem_offset_t base_offset; uint32 module_inst_struct_size = offsetof(WASMModuleInstance, global_table_data.bytes); uint64 module_inst_mem_inst_size; @@ -2305,10 +2329,12 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, (uint64)memory->num_bytes_per_page * memory->cur_page_count; bh_assert(memory_data || memory_size == 0); - bh_assert(data_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_I32_CONST - || data_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL); + bh_assert( + data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL + || (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + && !memory->is_memory64) + || (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I64_CONST + && memory->is_memory64)); if (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { if (!check_global_init_expr(module, @@ -2319,23 +2345,48 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, if (!globals || globals[data_seg->base_offset.u.global_index].type - != VALUE_TYPE_I32) { + != (memory->is_memory64 ? VALUE_TYPE_I64 + : VALUE_TYPE_I32)) { set_error_buf(error_buf, error_buf_size, "data segment does not fit"); goto fail; } - base_offset = - globals[data_seg->base_offset.u.global_index].initial_value.i32; +#if WASM_ENABLE_MEMORY64 != 0 + if (memory->is_memory64) { + base_offset = + (uint64)globals[data_seg->base_offset.u.global_index] + .initial_value.i64; + } + else +#endif + { + base_offset = + (uint32)globals[data_seg->base_offset.u.global_index] + .initial_value.i32; + } } else { - base_offset = (uint32)data_seg->base_offset.u.i32; +#if WASM_ENABLE_MEMORY64 != 0 + if (memory->is_memory64) { + base_offset = (uint64)data_seg->base_offset.u.i64; + } + else +#endif + { + base_offset = (uint32)data_seg->base_offset.u.i32; + } } /* check offset */ if (base_offset > memory_size) { - LOG_DEBUG("base_offset(%d) > memory_size(%d)", base_offset, +#if WASM_ENABLE_MEMORY64 != 0 + LOG_DEBUG("base_offset(%" PRIu64 ") > memory_size(%" PRIu64 ")", + base_offset, memory_size); +#else + LOG_DEBUG("base_offset(%u) > memory_size(%" PRIu64 ")", base_offset, memory_size); +#endif #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 set_error_buf(error_buf, error_buf_size, "out of bounds memory access"); @@ -2349,8 +2400,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, /* check offset + length(could be zero) */ length = data_seg->data_length; if ((uint64)base_offset + length > memory_size) { - LOG_DEBUG("base_offset(%d) + length(%d) > memory_size(%d)", +#if WASM_ENABLE_MEMORY64 != 0 + LOG_DEBUG("base_offset(%" PRIu64 + ") + length(%d) > memory_size(%" PRIu64 ")", base_offset, length, memory_size); +#else + LOG_DEBUG("base_offset(%u) + length(%d) > memory_size(%" PRIu64 ")", + base_offset, length, memory_size); +#endif #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 set_error_buf(error_buf, error_buf_size, "out of bounds memory access"); @@ -3311,7 +3368,8 @@ wasm_module_malloc_internal(WASMModuleInstance *module_inst, wasm_set_exception(module_inst, "app heap corrupted"); } else { - LOG_WARNING("warning: allocate %u bytes memory failed", size); + LOG_WARNING("warning: allocate %" PRIu64 " bytes memory failed", + size); } return 0; } @@ -3510,7 +3568,7 @@ call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 tbl_elem_idx, } #if WASM_ENABLE_GC == 0 - func_idx = tbl_elem_val; + func_idx = (uint32)tbl_elem_val; #else func_idx = wasm_func_obj_get_func_idx_bound((WASMFuncObjectRef)tbl_elem_val); @@ -4295,11 +4353,21 @@ llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx, } if (tbl_inst->cur_size > UINT32_MAX - inc_size) { /* integer overflow */ +#if WASM_ENABLE_SPEC_TEST == 0 + LOG_WARNING("table grow (%" PRIu32 "-> %" PRIu32 + ") failed because of integer overflow", + tbl_inst->cur_size, inc_size); +#endif return (uint32)-1; } total_size = tbl_inst->cur_size + inc_size; if (total_size > tbl_inst->max_size) { +#if WASM_ENABLE_SPEC_TEST == 0 + LOG_WARNING("table grow (%" PRIu32 "-> %" PRIu32 + ") failed because of over max size", + tbl_inst->cur_size, inc_size); +#endif return (uint32)-1; } @@ -4336,6 +4404,22 @@ llvm_jit_obj_is_instance_of(WASMModuleInstance *module_inst, return wasm_obj_is_instance_of(gc_obj, type_index, types, type_count); } +bool +llvm_jit_func_type_is_super_of(WASMModuleInstance *module_inst, + uint32 type_idx1, uint32 type_idx2) +{ + WASMModule *module = module_inst->module; + WASMType **types = module->types; + + if (type_idx1 == type_idx2) + return true; + + bh_assert(types[type_idx1]->type_flag == WASM_TYPE_FUNC); + bh_assert(types[type_idx2]->type_flag == WASM_TYPE_FUNC); + return wasm_func_type_is_super_of((WASMFuncType *)types[type_idx1], + (WASMFuncType *)types[type_idx2]); +} + WASMRttTypeRef llvm_jit_rtt_type_new(WASMModuleInstance *module_inst, uint32 type_index) { @@ -4541,8 +4625,8 @@ wasm_set_module_name(WASMModule *module, const char *name, char *error_buf, return false; module->name = - wasm_const_str_list_insert((const uint8 *)name, strlen(name), module, - false, error_buf, error_buf_size); + wasm_const_str_list_insert((const uint8 *)name, (uint32)strlen(name), + module, false, error_buf, error_buf_size); return module->name != NULL; } @@ -4550,4 +4634,4 @@ const char * wasm_get_module_name(WASMModule *module) { return module->name; -} \ No newline at end of file +} diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 5933e6a9c..4249eb5c1 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -103,7 +103,7 @@ struct WASMMemoryInstance { /* Whether the memory is shared */ uint8 is_shared_memory; - /* TODO: Memory64 whether the memory has 64-bit memory addresses */ + /* Whether the memory has 64-bit memory addresses */ uint8 is_memory64; /* Reference count of the memory instance: @@ -508,7 +508,7 @@ wasm_load(uint8 *buf, uint32 size, #if WASM_ENABLE_MULTI_MODULE != 0 bool main_module, #endif - char *error_buf, uint32 error_buf_size); + const LoadArgs *args, char *error_buf, uint32 error_buf_size); WASMModule * wasm_load_from_sections(WASMSection *section_list, char *error_buf, @@ -811,6 +811,11 @@ bool llvm_jit_obj_is_instance_of(WASMModuleInstance *module_inst, WASMObjectRef gc_obj, uint32 type_index); +/* Whether func type1 is one of super types of func type2 */ +bool +llvm_jit_func_type_is_super_of(WASMModuleInstance *module_inst, + uint32 type_idx1, uint32 type_idx2); + WASMRttTypeRef llvm_jit_rtt_type_new(WASMModuleInstance *module_inst, uint32 type_index); diff --git a/core/iwasm/libraries/debug-engine/handler.c b/core/iwasm/libraries/debug-engine/handler.c index 8d451b1a3..905ca2f7c 100644 --- a/core/iwasm/libraries/debug-engine/handler.c +++ b/core/iwasm/libraries/debug-engine/handler.c @@ -309,9 +309,11 @@ handle_general_query(WASMGDBServer *server, char *payload) } if (!strcmp(name, "WasmData")) { + write_packet(server, ""); } if (!strcmp(name, "WasmMem")) { + write_packet(server, ""); } if (!strcmp(name, "Symbol")) { @@ -447,7 +449,7 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid) "thread-pcs:%" PRIx64 ";00:%s;reason:%s;", pc, pc_string, "trace"); } - else if (status > 0) { + else { /* status > 0 (== 0 is checked at the function beginning) */ len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, "thread-pcs:%" PRIx64 ";00:%s;reason:%s;", pc, pc_string, "signal"); diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 30055e634..b3fa57d72 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -1123,7 +1123,8 @@ posix_memalign_wrapper(wasm_exec_env_t exec_env, void **memptr, int32 align, wasm_module_inst_t module_inst = get_module_inst(exec_env); void *p = NULL; - *((int32 *)memptr) = module_malloc(size, (void **)&p); + /* TODO: for memory 64, module_malloc may return uint64 offset */ + *((uint32 *)memptr) = (uint32)module_malloc(size, (void **)&p); if (!p) return -1; diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 7aa3444f9..2ac381033 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -17,7 +17,7 @@ void wasm_runtime_set_exception(wasm_module_inst_t module, const char *exception); uint32 -wasm_runtime_module_realloc(wasm_module_inst_t module, uint32 ptr, uint32 size, +wasm_runtime_module_realloc(wasm_module_inst_t module, uint64 ptr, uint64 size, void **p_native_addr); /* clang-format off */ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h index f00719113..01f89847e 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#ifndef _BLOCKING_OP_H_ +#define _BLOCKING_OP_H_ + #include "bh_platform.h" #include "wasm_export.h" @@ -57,3 +60,5 @@ __wasi_errno_t blocking_op_poll(wasm_exec_env_t exec_env, os_poll_file_handle *pfds, os_nfds_t nfds, int timeout, int *retp); #endif + +#endif /* end of _BLOCKING_OP_H_ */ diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index ac8957501..ac4deb92c 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -558,6 +558,7 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) aux_stack_size)) { goto fail3; } + new_exec_env->is_aux_stack_allocated = true; /* Inherit suspend_flags of parent thread */ new_exec_env->suspend_flags.flags = @@ -603,7 +604,9 @@ wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env) exec_env_tls = exec_env; } - /* Free aux stack space */ + /* Free aux stack space which was allocated in + wasm_cluster_spawn_exec_env */ + bh_assert(exec_env_tls->is_aux_stack_allocated); wasm_cluster_free_aux_stack(exec_env_tls, (uint64)exec_env->aux_stack_bottom); @@ -655,7 +658,9 @@ thread_manager_start_routine(void *arg) #endif /* Free aux stack space */ - wasm_cluster_free_aux_stack(exec_env, (uint64)exec_env->aux_stack_bottom); + if (exec_env->is_aux_stack_allocated) + wasm_cluster_free_aux_stack(exec_env, + (uint64)exec_env->aux_stack_bottom); os_mutex_lock(&cluster_list_lock); @@ -723,11 +728,13 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env, aux_stack_size)) { goto fail2; } + new_exec_env->is_aux_stack_allocated = true; } else { /* Disable aux stack */ new_exec_env->aux_stack_boundary = 0; new_exec_env->aux_stack_bottom = UINTPTR_MAX; + new_exec_env->is_aux_stack_allocated = false; } /* Inherit suspend_flags of parent thread */ @@ -1049,7 +1056,9 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) #endif /* Free aux stack space */ - wasm_cluster_free_aux_stack(exec_env, (uint64)exec_env->aux_stack_bottom); + if (exec_env->is_aux_stack_allocated) + wasm_cluster_free_aux_stack(exec_env, + (uint64)exec_env->aux_stack_bottom); /* App exit the thread, free the resources before exit native thread */ diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index b667fbe9f..4863527d6 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -785,8 +785,8 @@ gc_alloc_wo_internal(void *vheap, gc_size_t size, const char *file, int line) if (!hmu) goto finish; - /* Do we need to memset the memory to 0? */ - /* memset((char *)hmu + sizeof(*hmu), 0, tot_size - sizeof(*hmu)); */ + /* Don't memset the memory to improve performance, the caller should + decide whether to memset it or not */ bh_assert(hmu_get_size(hmu) >= tot_size); /* the total size allocated may be larger than diff --git a/core/shared/mem-alloc/ems/ems_gc.c b/core/shared/mem-alloc/ems/ems_gc.c index b0f14772b..26e83a975 100644 --- a/core/shared/mem-alloc/ems/ems_gc.c +++ b/core/shared/mem-alloc/ems/ems_gc.c @@ -114,8 +114,8 @@ sweep_instance_heap(gc_heap_t *heap) else { /* current block is still live */ if (last) { - tot_free += (char *)cur - (char *)last; - gci_add_fc(heap, last, (char *)cur - (char *)last); + tot_free += (gc_size_t)((char *)cur - (char *)last); + gci_add_fc(heap, last, (gc_size_t)((char *)cur - (char *)last)); hmu_mark_pinuse(last); last = NULL; } @@ -132,8 +132,8 @@ sweep_instance_heap(gc_heap_t *heap) bh_assert(cur == end); if (last) { - tot_free += (char *)cur - (char *)last; - gci_add_fc(heap, last, (char *)cur - (char *)last); + tot_free += (gc_size_t)((char *)cur - (char *)last); + gci_add_fc(heap, last, (gc_size_t)((char *)cur - (char *)last)); hmu_mark_pinuse(last); } @@ -449,7 +449,9 @@ gci_gc_heap(void *h) LOG_VERBOSE("#reclaim instance heap %p", heap); - gct_vm_gc_prepare(); + /* TODO: get exec_env of current thread when GC multi-threading + is enabled, and pass it to runtime */ + gct_vm_gc_prepare(NULL); gct_vm_mutex_lock(&heap->lock); heap->is_doing_reclaim = 1; @@ -459,7 +461,9 @@ gci_gc_heap(void *h) heap->is_doing_reclaim = 0; gct_vm_mutex_unlock(&heap->lock); - gct_vm_gc_finished(); + /* TODO: get exec_env of current thread when GC multi-threading + is enabled, and pass it to runtime */ + gct_vm_gc_finished(NULL); LOG_VERBOSE("#reclaim instance heap %p done", heap); diff --git a/core/shared/mem-alloc/mem_alloc.c b/core/shared/mem-alloc/mem_alloc.c index 1f9e03d5a..df1a4de4c 100644 --- a/core/shared/mem-alloc/mem_alloc.c +++ b/core/shared/mem-alloc/mem_alloc.c @@ -77,13 +77,13 @@ mem_allocator_free_with_gc(mem_allocator_t allocator, void *ptr) void mem_allocator_enable_gc_reclaim(mem_allocator_t allocator, void *exec_env) { - return gc_enable_gc_reclaim((gc_handle_t)allocator, exec_env); + gc_enable_gc_reclaim((gc_handle_t)allocator, exec_env); } #else void mem_allocator_enable_gc_reclaim(mem_allocator_t allocator, void *cluster) { - return gc_enable_gc_reclaim((gc_handle_t)allocator, cluster); + gc_enable_gc_reclaim((gc_handle_t)allocator, cluster); } #endif diff --git a/core/shared/platform/common/posix/posix_file.c b/core/shared/platform/common/posix/posix_file.c index 20f94fba3..e7c8383c3 100644 --- a/core/shared/platform/common/posix/posix_file.c +++ b/core/shared/platform/common/posix/posix_file.c @@ -823,7 +823,7 @@ os_fadvise(os_file_handle handle, __wasi_filesize_t offset, int ret = posix_fadvise(handle, (off_t)offset, (off_t)length, nadvice); - if (ret < 0) + if (ret != 0) return convert_errno(ret); return __WASI_ESUCCESS; diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index c9a7e5897..c76abf137 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -65,9 +65,11 @@ os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) /* integer overflow */ return NULL; +#if WASM_ENABLE_MEMORY64 == 0 if (request_size > 16 * (uint64)UINT32_MAX) - /* at most 16 G is allowed */ + /* at most 64 G is allowed */ return NULL; +#endif if (prot & MMAP_PROT_READ) map_prot |= PROT_READ; diff --git a/core/shared/platform/esp-idf/espidf_memmap.c b/core/shared/platform/esp-idf/espidf_memmap.c index 6b1b6f045..21f186b90 100644 --- a/core/shared/platform/esp-idf/espidf_memmap.c +++ b/core/shared/platform/esp-idf/espidf_memmap.c @@ -55,7 +55,24 @@ os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) #else uint32_t mem_caps = MALLOC_CAP_8BIT; #endif - return heap_caps_malloc(size, mem_caps); + void *buf_origin = + heap_caps_malloc(size + 4 + sizeof(uintptr_t), mem_caps); + if (!buf_origin) { + return NULL; + } + + // Memory allocation with MALLOC_CAP_SPIRAM or MALLOC_CAP_8BIT will + // return 4-byte aligned Reserve extra 4 byte to fixup alignment and + // size for the pointer to the originally allocated address + void *buf_fixed = buf_origin + sizeof(void *); + if ((uintptr_t)buf_fixed & (uintptr_t)0x7) { + buf_fixed = (void *)((uintptr_t)(buf_fixed + 4) & (~(uintptr_t)7)); + } + + uintptr_t *addr_field = buf_fixed - sizeof(uintptr_t); + *addr_field = (uintptr_t)buf_origin; + + return buf_fixed; } } diff --git a/core/shared/platform/esp-idf/espidf_platform.c b/core/shared/platform/esp-idf/espidf_platform.c index 9c0d02e62..8fea32546 100644 --- a/core/shared/platform/esp-idf/espidf_platform.c +++ b/core/shared/platform/esp-idf/espidf_platform.c @@ -6,6 +6,12 @@ #include "platform_api_vmcore.h" #include "platform_api_extension.h" +#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) \ + && (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0)) +#define UTIMENSAT_TIMESPEC_POINTER 1 +#define FUTIMENS_TIMESPEC_POINTER 1 +#endif + int bh_platform_init() { @@ -234,7 +240,13 @@ unlinkat(int fd, const char *path, int flag) } int -utimensat(int fd, const char *path, const struct timespec ts[2], int flag) +utimensat(int fd, const char *path, +#if UTIMENSAT_TIMESPEC_POINTER + const struct timespec *ts, +#else + const struct timespec ts[2], +#endif + int flag) { errno = ENOSYS; return -1; @@ -257,7 +269,13 @@ ftruncate(int fd, off_t length) #endif int -futimens(int fd, const struct timespec times[2]) +futimens(int fd, +#if FUTIMENS_TIMESPEC_POINTER + const struct timespec *times +#else + const struct timespec times[2] +#endif +) { errno = ENOSYS; return -1; diff --git a/core/shared/platform/nuttx/shared_platform.cmake b/core/shared/platform/nuttx/shared_platform.cmake index ff70cc031..d691068f2 100644 --- a/core/shared/platform/nuttx/shared_platform.cmake +++ b/core/shared/platform/nuttx/shared_platform.cmake @@ -8,6 +8,10 @@ add_definitions(-DBH_PLATFORM_NUTTX) include_directories(${PLATFORM_SHARED_DIR}) include_directories(${PLATFORM_SHARED_DIR}/../include) +include (${CMAKE_CURRENT_LIST_DIR}/../common/posix/platform_api_posix.cmake) + +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) if (WAMR_BUILD_LIBC_WASI EQUAL 1) @@ -16,6 +20,7 @@ if (WAMR_BUILD_LIBC_WASI EQUAL 1) set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE}) endif () -include (${CMAKE_CURRENT_LIST_DIR}/../common/memory/platform_api_memory.cmake) -set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE} ${PLATFORM_COMMON_MEMORY_SOURCE}) +set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE} ${PLATFORM_COMMON_POSIX_SOURCE} ${UNCOMMON_SHARED_SOURCE}) +# remove posix_memmap.c for NuttX +list(REMOVE_ITEM ${PLATFORM_SHARED_SOURCE} ${PLATFORM_COMMON_POSIX_DIR}/posix_memmap.c) diff --git a/core/shared/platform/zephyr/zephyr_thread.c b/core/shared/platform/zephyr/zephyr_thread.c index 105d53993..53ca71f62 100644 --- a/core/shared/platform/zephyr/zephyr_thread.c +++ b/core/shared/platform/zephyr/zephyr_thread.c @@ -577,4 +577,34 @@ os_thread_get_stack_boundary() void os_thread_jit_write_protect_np(bool enabled) -{} \ No newline at end of file +{} + +int +os_thread_detach(korp_tid thread) +{ + (void)thread; + return BHT_OK; +} + +void +os_thread_exit(void *retval) +{ + (void)retval; + os_thread_cleanup(); + k_thread_abort(k_current_get()); +} + +int +os_cond_broadcast(korp_cond *cond) +{ + os_thread_wait_node *node; + k_mutex_lock(&cond->wait_list_lock, K_FOREVER); + node = cond->thread_wait_list; + while (node) { + os_thread_wait_node *next = node->next; + k_sem_give(&node->sem); + node = next; + } + k_mutex_unlock(&cond->wait_list_lock); + return BHT_OK; +} diff --git a/core/shared/utils/runtime_timer.c b/core/shared/utils/runtime_timer.c index b9ace567f..9d390c214 100644 --- a/core/shared/utils/runtime_timer.c +++ b/core/shared/utils/runtime_timer.c @@ -394,7 +394,7 @@ handle_expired_timers(timer_ctx_t ctx, app_timer_t *expired) operation may change expired->next */ expired = expired->next; if (t->is_periodic) { - /* if it is repeating, then reschedule it; */ + /* if it is repeating, then reschedule it */ reschedule_timer(ctx, t); } else { diff --git a/doc/build_wamr.md b/doc/build_wamr.md index a9ffca204..5598ea364 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -76,6 +76,11 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM #### **Enable bulk memory feature** - **WAMR_BUILD_BULK_MEMORY**=1/0, default to disable if not set +#### **Enable memory64 feature** +- **WAMR_BUILD_MEMORY64**=1/0, default to disable if not set + +> Note: Currently, the memory64 feature is only supported in classic interpreter running mode. + #### **Enable thread manager** - **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set @@ -129,6 +134,14 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM - **WAMR_BUILD_SIMD**=1/0, default to enable if not set > Note: only supported in AOT mode x86-64 target. +#### **Enable Exception Handling** +- **WAMR_BUILD_EXCE_HANDLING**=1/0, default to disable if not set + +> Note: Currently, the exception handling feature is only supported in classic interpreter running mode. + +#### **Enable Garbage Collection** +- **WAMR_BUILD_GC**=1/0, default to disable if not set + #### **Configure Debug** - **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set @@ -241,6 +254,10 @@ Currently we only profile the memory consumption of module, module_instance and > See [Enable segue optimization for wamrc when generating the aot file](./perf_tune.md#3-enable-segue-optimization-for-wamrc-when-generating-the-aot-file) for more details. +#### **User defined linear memory allocator** +- **WAMR_BUILD_ALLOC_WITH_USAGE**=1/0, default to disable if not set +> Notes: by default, the linear memory is allocated by system. when it's set to 1 and Alloc_With_Allocator is selected, it will be allocated by customer. + #### **Enable running PGO(Profile-Guided Optimization) instrumented AOT file** - **WAMR_BUILD_STATIC_PGO**=1/0, default to disable if not set > Note: See [Use the AOT static PGO method](./perf_tune.md#5-use-the-aot-static-pgo-method) for more details. @@ -264,6 +281,10 @@ Currently we only profile the memory consumption of module, module_instance and - **WAMR_BUILD_QUICK_AOT_ENTRY**=1/0, enable registering quick call entries to speedup the aot/jit func call process, default to enable if not set > Note: See [Refine callings to AOT/JIT functions from host native](./perf_tune.md#83-refine-callings-to-aotjit-functions-from-host-native) for more details. +#### **Enable AOT intrinsics** +- **WAMR_BUILD_AOT_INTRINSICS**=1/0, enable the AOT intrinsic functions, default to enable if not set. These functions can be called from the AOT code when `--disable-llvm-intrinsics` flag or `--enable-builtin-intrinsics=` flag is used by wamrc to generate the AOT file. +> Note: See [Tuning the XIP intrinsic functions](./xip.md#tuning-the-xip-intrinsic-functions) for more details. + #### **Configurale memory access boundary check** - **WAMR_CONFIGUABLE_BOUNDS_CHECKS**=1/0, default to disable if not set > Note: If it is enabled, allow to run `iwasm --disable-bounds-checks` to disable the memory access boundary checks for interpreter mode. diff --git a/idf_component.yml b/idf_component.yml new file mode 100644 index 000000000..ff25b32cb --- /dev/null +++ b/idf_component.yml @@ -0,0 +1,15 @@ +version: "2.0.0" +description: WebAssembly Micro Runtime - A lightweight standalone WebAssembly (Wasm) runtime with small footprint, high performance and highly configurable features +url: https://bytecodealliance.org/ +repository: https://github.com/bytecodealliance/wasm-micro-runtime.git +documentation: https://wamr.gitbook.io/ +issues: https://github.com/bytecodealliance/wasm-micro-runtime/issues +dependencies: + idf: ">=4.4" +targets: + - esp32 + - esp32s3 + - esp32c3 + - esp32c6 +examples: + - path: product-mini/platforms/esp-idf \ No newline at end of file diff --git a/product-mini/platforms/esp-idf/CMakeLists.txt b/product-mini/platforms/esp-idf/CMakeLists.txt index d8a3d2f96..8472df8dd 100644 --- a/product-mini/platforms/esp-idf/CMakeLists.txt +++ b/product-mini/platforms/esp-idf/CMakeLists.txt @@ -6,7 +6,4 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -set (COMPONENTS ${IDF_TARGET} main freertos esptool_py wamr) -list(APPEND EXTRA_COMPONENT_DIRS "$ENV{WAMR_PATH}/build-scripts/esp-idf") - project(wamr-simple) \ No newline at end of file diff --git a/product-mini/platforms/esp-idf/main/CMakeLists.txt b/product-mini/platforms/esp-idf/main/CMakeLists.txt index 55e725670..1bb61bad9 100644 --- a/product-mini/platforms/esp-idf/main/CMakeLists.txt +++ b/product-mini/platforms/esp-idf/main/CMakeLists.txt @@ -2,5 +2,4 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception idf_component_register(SRCS "main.c" - INCLUDE_DIRS "." - REQUIRES wamr) + INCLUDE_DIRS ".") diff --git a/product-mini/platforms/esp-idf/main/idf_component.yml b/product-mini/platforms/esp-idf/main/idf_component.yml new file mode 100644 index 000000000..1c05f476e --- /dev/null +++ b/product-mini/platforms/esp-idf/main/idf_component.yml @@ -0,0 +1,7 @@ +## IDF Component Manager Manifest File +dependencies: + wasm-micro-runtime: + version: "^2" + override_path: "../../../.." + idf: + version: ">=4.4" \ No newline at end of file diff --git a/product-mini/platforms/esp-idf/main/main.c b/product-mini/platforms/esp-idf/main/main.c index fbfb04c21..1a34096d7 100644 --- a/product-mini/platforms/esp-idf/main/main.c +++ b/product-mini/platforms/esp-idf/main/main.c @@ -12,11 +12,7 @@ #include "esp_log.h" -#ifdef CONFIG_IDF_TARGET_ESP32S3 #define IWASM_MAIN_STACK_SIZE 5120 -#else -#define IWASM_MAIN_STACK_SIZE 4096 -#endif #define LOG_TAG "wamr" diff --git a/product-mini/platforms/nuttx/CMakeLists.txt b/product-mini/platforms/nuttx/CMakeLists.txt new file mode 100644 index 000000000..e9fe5a9e3 --- /dev/null +++ b/product-mini/platforms/nuttx/CMakeLists.txt @@ -0,0 +1,203 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# select platform configuration setting WAMR_BUILD_TARGET +set(WAMR_BUILD_PLATFORM nuttx) + +if(CONFIG_ARCH_ARMV6M) + set(WAMR_BUILD_TARGET THUMBV6M) +elseif(CONFIG_ARCH_ARMV7A) + set(WAMR_BUILD_TARGET THUMBV7) +elseif(CONFIG_ARCH_ARMV7M) + set(WAMR_BUILD_TARGET THUMBV7EM) +elseif(CONFIG_ARCH_ARMV8M) + set(WAMR_BUILD_TARGET THUMBV8M) +elseif(CONFIG_ARCH_X86) + set(WAMR_BUILD_TARGET X86_32) +elseif(CONFIG_ARCH_X86_64) + set(WAMR_BUILD_TARGET X86_64) +elseif(CONFIG_ARCH_XTENSA) + set(WAMR_BUILD_TARGET XTENSA) +elseif(CONFIG_ARCH_RV64GC OR CONFIG_ARCH_RV64) + set(WAMR_BUILD_TARGET RISCV64) +elseif(CONFIG_ARCH_RV32IM OR CONFIG_ARCH_RV32) + set(WAMR_BUILD_TARGET RISCV32) +elseif(CONFIG_ARCH_SIM) + if(CONFIG_SIM_M32 OR CONFIG_HOST_X86) + set(WAMR_BUILD_TARGET X86_32) + elseif(CONFIG_HOST_ARM) + set(WAMR_BUILD_TARGET ARM) + elseif(CONFIG_HOST_ARM64) + set(WAMR_BUILD_TARGET AARCH64) + else() + set(WAMR_BUILD_TARGET X86_64) + endif() + if(CONFIG_HOST_MACOS) + add_definitions(-DBH_PLATFORM_DARWIN) + endif() +endif() + +if(CONFIG_INTERPRETERS_WAMR_LOG) + add_definitions(-DWASM_ENABLE_LOG=1) +else() + add_definitions(-DWASM_ENABLE_LOG=0) +endif() + +if(CONFIG_INTERPRETERS_WAMR_AOT_WORD_ALIGN_READ) + add_definitions(-DWASM_ENABLE_WORD_ALIGN_READ=1) +else() + add_definitions(-DWASM_ENABLE_WORD_ALIGN_READ=0) +endif() + +if(CONFIG_INTERPRETERS_WAMR_STACK_GUARD_SIZE) + add_definitions(-DWASM_STACK_GUARD_SIZE=0) +else() + add_definitions( + -DWASM_STACK_GUARD_SIZE=${CONFIG_INTERPRETERS_WAMR_STACK_GUARD_SIZE}) +endif() + +if(CONFIG_INTERPRETERS_WAMR_MEMORY_TRACING) + add_definitions(-DWASM_ENABLE_MEMORY_TRACING=1) +else() + add_definitions(-DWASM_ENABLE_MEMORY_TRACING=0) +endif() + +if(CONFIG_INTERPRETERS_WAMR_SHARED_MEMORY) + set(WAMR_BUILD_SHARED_MEMORY 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_BULK_MEMORY) + set(WAMR_BUILD_BULK_MEMORY 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_AOT_STACK_FRAME) + set(WAMR_BUILD_AOT_STACK_FRAME 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_PERF_PROFILING) + set(WAMR_BUILD_PERF_PROFILING 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_GC) + set(WAMR_BUILD_GC 1) + set(WAMR_BUILD_STRINGREF 1) + set(WAMR_BUILD_REF_TYPES 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_GC_MANUALLY) + add_definitions(-DWASM_GC_MANUALLY=1) +else() + add_definitions(-DWASM_GC_MANUALLY=0) +endif() + +if(CONFIG_INTERPRETERS_WAMR_GC_PERF_PROFILING) + set(WAMR_BUILD_GC_PERF_PROFILING 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_ENABLE_EXCE_HANDLING) + set(WAMR_BUILD_EXCE_HANDLING 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_TAIL_CALL) + set(WAMR_BUILD_TAIL_CALL 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_MEMORY_PROFILING) + set(WAMR_BUILD_MEMORY_PROFILING 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_MULTI_MODULE) + set(WAMR_BUILD_MULTI_MODULE 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_LIB_PTHREAD_SEMAPHORE) + set(WAMR_BUILD_LIB_PTHREAD_SEMAPHORE 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_DISABLE_HW_BOUND_CHECK) + set(WAMR_DISABLE_HW_BOUND_CHECK 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_CUSTOM_NAME_SECTIONS) + set(WAMR_BUILD_CUSTOM_NAME_SECTION 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_GLOBAL_HEAP_POOL) + set(WAMR_BUILD_GLOBAL_HEAP_POOL 1) + math(EXPR _HEAP_SIZE_ + "${CONFIG_INTERPRETERS_WAMR_GLOBAL_HEAP_POOL_SIZE} * 1024") + set(WAMR_BUILD_GLOBAL_HEAP_SIZE ${_HEAP_SIZE_}) +endif() + +if (CONFIG_INTERPRETERS_WAMR_MEM_ALLOC_WITH_USAGE) + set(WAMR_BUILD_MEM_ALLOC_WITH_USAGE 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST) + set(WAMR_BUILD_SPEC_TEST 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_REF_TYPES) + set(WAMR_BUILD_REF_TYPES 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_CLASSIC) + # include iwasm_interp.cmake + set(WAMR_BUILD_INTERP 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_FAST) + # enable iwasm_interp.cmake + set(WAMR_BUILD_FAST_INTERP 1) +endif() + +if((CONFIG_INTERPRETERS_WAMR_FAST OR CONFIG_INTERPRETERS_WAMR_CLASSIC) + AND CONFIG_INTERPRETERS_WAMR_MINILOADER) + # enable iwasm_interp.cmake + set(WAMR_BUILD_MINI_LOADER 1) +else() + set(WAMR_BUILD_MINI_LOADER 0) +endif() + +if(CONFIG_INTERPRETERS_WAMR_AOT) + # include iwasm_aot.cmake + set(WAMR_BUILD_AOT 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_DEBUG_INTERP) + # include debug_engine.cmake + set(WAMR_BUILD_DEBUG_INTERP 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN) + # include libc_builtin.cmake + set(WAMR_BUILD_LIBC_BUILTIN 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_LIBC_WASI) + # include libc_wasi.cmake + set(WAMR_BUILD_LIBC_WASI 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_THREAD_MGR) + # include thread_mgr.cmake + set(WAMR_BUILD_THREAD_MGR 1) +endif() + +if(CONFIG_INTERPRETERS_WAMR_LIB_PTHREAD) + # include lib_pthread.cmake + set(WAMR_BUILD_LIB_PTHREAD 1) +endif() + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) + +# enable WAMR build system +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 + -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 e414a7cda..7aac0e358 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -373,6 +373,11 @@ CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=1 CFLAGS += -DWASM_GLOBAL_HEAP_SIZE="$(CONFIG_INTERPRETERS_WAMR_GLOBAL_HEAP_POOL_SIZE) * 1024" else CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=0 +ifeq ($(CONFIG_INTERPRETERS_WAMR_MEM_ALLOC_WITH_USAGE),y) +CFLAGS += -DWASM_MEM_ALLOC_WITH_USAGE=1 +else +CFLAGS += -DWASM_MEM_ALLOC_WITH_USAGE=0 +endif endif ifeq ($(CONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST),y) diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index 37ee0cb87..cb0581ce2 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -445,6 +445,9 @@ static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 }; #else static void * malloc_func( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + mem_alloc_usage_t usage, +#endif #if WASM_MEM_ALLOC_WITH_USER_DATA != 0 void *user_data, #endif @@ -455,6 +458,9 @@ malloc_func( static void * realloc_func( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + mem_alloc_usage_t usage, bool full_size_mmaped, +#endif #if WASM_MEM_ALLOC_WITH_USER_DATA != 0 void *user_data, #endif @@ -465,6 +471,9 @@ realloc_func( static void free_func( +#if WASM_MEM_ALLOC_WITH_USAGE != 0 + mem_alloc_usage_t usage, +#endif #if WASM_MEM_ALLOC_WITH_USER_DATA != 0 void *user_data, #endif @@ -675,7 +684,7 @@ main(int argc, char *argv[]) #endif #if WASM_ENABLE_GC != 0 else if (!strncmp(argv[0], "--gc-heap-size=", 15)) { - if (argv[0][21] == '\0') + if (argv[0][15] == '\0') return print_help(); gc_heap_size = atoi(argv[0] + 15); } @@ -851,7 +860,8 @@ main(int argc, char *argv[]) #if WASM_ENABLE_DEBUG_INTERP != 0 init_args.instance_port = instance_port; if (ip_addr) - strcpy(init_args.ip_addr, ip_addr); + /* ensure that init_args.ip_addr is null terminated */ + strncpy(init_args.ip_addr, ip_addr, sizeof(init_args.ip_addr) - 1); #endif /* initialize runtime environment */ diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index 6461e9172..35a489721 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -464,7 +464,9 @@ main(int argc, char *argv[]) #if WASM_ENABLE_DEBUG_INTERP != 0 init_args.instance_port = instance_port; if (ip_addr) - strcpy(init_args.ip_addr, ip_addr); + /* ensure that init_args.ip_addr is null terminated */ + strncpy_s(init_args.ip_addr, sizeof(init_args.ip_addr) - 1, ip_addr, + strlen(ip_addr)); #endif /* initialize runtime environment */ diff --git a/samples/debug-tools/CMakeLists.txt b/samples/debug-tools/CMakeLists.txt index 5143462a3..ce06029a5 100644 --- a/samples/debug-tools/CMakeLists.txt +++ b/samples/debug-tools/CMakeLists.txt @@ -7,6 +7,14 @@ include(CheckPIESupported) project(debug_tools_sample) +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +find_package(WASISDK REQUIRED) + +option(SOURCE_MAP_DEMO "Enable source map demo" OFF) +if (SOURCE_MAP_DEMO) + find_package(EMSCRIPTEN 3.1.50 REQUIRED) +endif () + ################ runtime settings ################ string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) if (APPLE) @@ -61,7 +69,30 @@ include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) ################ wasm application ################ -add_subdirectory(wasm-apps) +include(ExternalProject) + +# wasm32-wasi +ExternalProject_Add(wasm33-wasi + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps" + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps -B build + -DWASI_SDK_PREFIX=${WASISDK_HOME} + -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN} + BUILD_COMMAND ${CMAKE_COMMAND} --build build + INSTALL_COMMAND ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR} +) + +if (EMSCRIPTEN_FOUND) + # wasm32-emscripten + ExternalProject_Add(wasm32-emscripten + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps" + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps -B build + -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN_TOOLCHAIN} + -DCMAKE_VERBOSE_MAKEFILE=On + -DSOURCE_MAP_DEMO=On + BUILD_COMMAND ${CMAKE_COMMAND} --build build + INSTALL_COMMAND ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR}/emscripten + ) +endif () ################ wamr runtime ################ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) diff --git a/samples/debug-tools/README.md b/samples/debug-tools/README.md index 304778596..b0358b9e4 100644 --- a/samples/debug-tools/README.md +++ b/samples/debug-tools/README.md @@ -63,7 +63,7 @@ The output should be something like: at wasm-micro-runtime/samples/debug-tools/wasm-apps/trap.c:17:12 3: main at wasm-micro-runtime/samples/debug-tools/wasm-apps/trap.c:24:5 -4: +4: __main_void at unknown:?:? 5: _start ``` @@ -79,3 +79,55 @@ $ python3 ../../../test-tools/addr2line/addr2line.py \ --wasm-file wasm-apps/trap.wasm \ call_stack.txt --no-addr ``` + +#### sourcemap + +This script also supports _sourcemap_ which is produced by [_emscripten_](https://emscripten.org/docs/tools_reference/emcc.html). The _sourcemap_ is used to map the wasm function to the original source file. To use it, add `-gsource-map` option to _emcc_ command line. The output should be a section named "sourceMappingURL" and a separated file named "_.map_. + +If the wasm file is with _sourcemap_, the script will use it to get the source file and line info. It needs an extra command line option `--emsdk` to specify the path of _emsdk_. The script will use _emsymbolizer_ to query the source file and line info. + +````bash +$ python3 ../../../test-tools/addr2line/addr2line.py \ + --wasi-sdk /opt/wasi-sdk \ + --wabt /opt/wabt \ + --wasm-file emscripten/wasm-apps/trap.wasm \ + --emsdk /opt/emsdk \ + call_stack.from_wasm_w_sourcemap.txt + +The output should be something like: + +```text +1: c + at ../../../../../wasm-apps/trap.c:5:1 +2: b + at ../../../../../wasm-apps/trap.c:11:12 +3: a + at ../../../../../wasm-apps/trap.c:17:12 +4: main + at ../../../../../wasm-apps/trap.c:24:5 +5: __main_void + at ../../../../../../../../../emsdk/emscripten/system/lib/standalone/__main_void.c:53:10 +6: _start + at ../../../../../../../../../emsdk/emscripten/system/lib/libc/crt1.c:27:3 +```` + +> The script assume the separated map file _.map_ is in the same directory as the wasm file. + +### Another approach + +If the wasm file is with "name" section, it is able to output function name in the stack trace. To achieve that, need to enable `WAMR_BUILD_LOAD_CUSTOM_SECTION` and `WAMR_BUILD_CUSTOM_NAME_SECTION`. If using .aot file, need to add `--emit-custom-sections=name` into wamrc command line options. + +Then the output should be something like + +```text +#00: 0x0159 - c +#01: 0x01b2 - b +#02: 0x0200 - a +#03: 0x026b - main +#04: 0x236b - __main_void +#05: 0x011f - _start + +Exception: unreachable +``` + +Also, it is able to use _addr2line.py_ to add file and line info to the stack trace. diff --git a/samples/debug-tools/cmake/FindEMSCRIPTEN.cmake b/samples/debug-tools/cmake/FindEMSCRIPTEN.cmake new file mode 100644 index 000000000..8f63ec545 --- /dev/null +++ b/samples/debug-tools/cmake/FindEMSCRIPTEN.cmake @@ -0,0 +1,45 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(FindPackageHandleStandardArgs) + +find_path(EMSCRIPTEN_HOME + NAMES upstream/emscripten + PATHS /opt/emsdk + NO_DEFAULT_PATH + NO_CMAKE_PATH + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH + REQUIRED +) + +find_file(EMSCRIPTEN_VERSION_FILE + NAMES emscripten-version.txt + PATHS ${EMSCRIPTEN_HOME}/upstream/emscripten + NO_DEFAULT_PATH + NO_CMAKE_PATH + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH + REQUIRED +) + +file(READ ${EMSCRIPTEN_VERSION_FILE} EMSCRIPTEN_VERSION_FILE_CONTENT) + +string(REGEX + MATCH + "[0-9]+\.[0-9]+(\.[0-9]+)*" + EMSCRIPTEN_VERSION + ${EMSCRIPTEN_VERSION_FILE_CONTENT} +) + +find_package_handle_standard_args(EMSCRIPTEN + REQUIRED_VARS EMSCRIPTEN_HOME + VERSION_VAR EMSCRIPTEN_VERSION + HANDLE_VERSION_RANGE +) + +if(EMSCRIPTEN_FOUND) + set(EMSCRIPTEN_TOOLCHAIN ${EMSCRIPTEN_HOME}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake) + set(EMCC ${EMSCRIPTEN_HOME}/upstream/emscripten/emcc) +endif() +mark_as_advanced(EMSCRIPTEN_TOOLCHAIN EMCC) diff --git a/samples/debug-tools/cmake/FindWAMRC.cmake b/samples/debug-tools/cmake/FindWAMRC.cmake new file mode 100644 index 000000000..20f9416f7 --- /dev/null +++ b/samples/debug-tools/cmake/FindWAMRC.cmake @@ -0,0 +1,27 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(FindPackageHandleStandardArgs) + +find_path(WAMRC_HOME + wamr-compiler + PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../../.. + NO_DEFAULT_PATH + NO_CMAKE_PATH + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH + REQUIRED +) + +find_file(WAMRC_BIN + wamrc + HINTS ${WAMRC_HOME}/wamr-compiler/build + NO_DEFAULT_PATH + NO_CMAKE_PATH + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_FIND_ROOT_PATH + REQUIRED +) + +find_package_handle_standard_args(WAMRC REQUIRED_VARS WAMRC_BIN) +mark_as_advanced(WAMRC_BIN) diff --git a/samples/debug-tools/cmake/FindWASISDK.cmake b/samples/debug-tools/cmake/FindWASISDK.cmake new file mode 100644 index 000000000..0caf374df --- /dev/null +++ b/samples/debug-tools/cmake/FindWASISDK.cmake @@ -0,0 +1,24 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(FindPackageHandleStandardArgs) + +file(GLOB WASISDK_SEARCH_PATH "/opt/wasi-sdk-*") +find_path(WASISDK_HOME + NAMES share/wasi-sysroot + PATHS ${WASISDK_SEARCH_PATH} + NO_DEFAULT_PATH + REQUIRED +) + +string(REGEX MATCH [0-9]+\.[0-9]+\.*[0-9]* WASISDK_VERSION ${WASISDK_HOME}) + +find_package_handle_standard_args(WASISDK REQUIRED_VARS WASISDK_HOME VERSION_VAR WASISDK_VERSION) + +if(WASISDK_FOUND) + set(WASISDK_CC_COMMAND ${WASISDK_HOME}/bin/clang) + set(WASISDK_CXX_COMMAND ${WASISDK_HOME}/bin/clang++) + set(WASISDK_TOOLCHAIN ${WASISDK_HOME}/share/cmake/wasi-sdk.cmake) + set(WASISDK_SYSROOT ${WASISDK_HOME}/share/wasi-sysroot) +endif() +mark_as_advanced(WASISDK_CC_COMMAND WASISDK_CXX_COMMAND WASISDK_TOOLCHAIN WASISDK_SYSROOT WASISDK_HOME) diff --git a/samples/debug-tools/wasm-apps/CMakeLists.txt b/samples/debug-tools/wasm-apps/CMakeLists.txt index 3ca8aff2a..527b5f37a 100644 --- a/samples/debug-tools/wasm-apps/CMakeLists.txt +++ b/samples/debug-tools/wasm-apps/CMakeLists.txt @@ -1,91 +1,58 @@ # Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -if (APPLE) - set (HAVE_FLAG_SEARCH_PATHS_FIRST 0) - set (CMAKE_C_LINK_FLAGS "") - set (CMAKE_CXX_LINK_FLAGS "") +cmake_minimum_required (VERSION 3.14) + +project (debut_tools_wasm) + +set (CMAKE_BUILD_TYPE Debug) # Otherwise no debug symbols (addr2line) + +list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../cmake) +find_package (WAMRC REQUIRED) + +option(SOURCE_MAP_DEMO "Enable source map demo" OFF) +if (SOURCE_MAP_DEMO) + find_package(EMSCRIPTEN 3.1.50 REQUIRED) endif () -if (NOT DEFINED WASI_SDK_DIR) - set (WASI_SDK_DIR "/opt/wasi-sdk") -endif () - -if (DEFINED WASI_SYSROOT) - set (CMAKE_SYSROOT "${WASI_SYSROOT}") -endif () - -set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") -set (CMAKE_ASM_COMPILER "${WASI_SDK_DIR}/bin/clang") -set (CMAKE_EXE_LINKER_FLAGS "-target wasm32-wasi") - -################ wabt and wamrc dependencies ################ -message(CHECK_START "Detecting WABT") -if(NOT (DEFINED WABT_DIR OR DEFINED CACHE{WABT_DIR})) - find_path(WABT_DIR - wabt - PATHS /opt - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH - ) - if(DEFINED WABT_DIR) - set(WABT_DIR ${WABT_DIR}/wabt) - endif() -endif() -if(WABT_DIR) - message(CHECK_PASS "found") -else() - message(CHECK_FAIL "not found") -endif() - -message(CHECK_START "Detecting WASM_OBJDUMP at ${WABT_DIR}") -find_program(WASM_OBJDUMP - wasm-objdump - PATHS "${WABT_DIR}/bin" - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH -) -if(WASM_OBJDUMP) - message(CHECK_PASS "found") -else() - message(CHECK_FAIL "not found") -endif() -if((NOT EXISTS ${WASM_OBJDUMP}) ) - message(FATAL_ERROR "Please make sure to have wasm-objdump under the path=${WABT_DIR}/bin ") -endif() - -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 the path=${WAMR_ROOT_DIR}/wamr-compiler/") -endif() - ################ wasm and aot compilation ################ function (compile_sample SOURCE_FILE) get_filename_component (FILE_NAME ${SOURCE_FILE} NAME_WLE) - set (WASM_MODULE ${FILE_NAME}.wasm) - add_executable (${WASM_MODULE} ${SOURCE_FILE}) - add_custom_target( - wasm_to_aot + ## wasm + set (WASM_FILE ${FILE_NAME}.wasm) + add_executable (${FILE_NAME} ${SOURCE_FILE}) + set_target_properties (${FILE_NAME} PROPERTIES SUFFIX .wasm) + + ## aot + set (AOT_FILE ${FILE_NAME}.aot) + add_custom_target ( + ${FILE_NAME}_aot ALL - DEPENDS ${WAMR_COMPILER} ${WASM_MODULE} + DEPENDS ${WAMRC_BIN} ${WASM_FILE} # Use --enable-dump-call-stack to generate stack trace (addr2line) - COMMAND ${WAMR_COMPILER} --size-level=0 --enable-dump-call-stack -o wasm-apps/trap.aot wasm-apps/trap.wasm - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND ${WAMRC_BIN} --size-level=0 --enable-dump-call-stack -o ${AOT_FILE} ${WASM_FILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) + + ## wasm + sourcemap + if (DEFINED EMSCRIPTEN) + add_custom_target( + ${FILE_NAME}_w_sourcemap + ALL + DEPENDS ${SOURCE_FILE} + COMMAND ${EMCC} -O0 -gsource-map -o ${FILE_NAME}.sourcemap.wasm ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + endif () + + ## install both + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${WASM_FILE} DESTINATION wasm-apps) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${AOT_FILE} DESTINATION wasm-apps) + if (DEFINED EMSCRIPTEN) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.sourcemap.wasm DESTINATION wasm-apps) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.sourcemap.wasm.map DESTINATION wasm-apps) + endif () endfunction () -set(CMAKE_BUILD_TYPE Debug) # Otherwise no debug symbols (addr2line) -compile_sample(trap.c) \ No newline at end of file +compile_sample(trap.c) diff --git a/samples/linux-perf/CMakeLists.txt b/samples/linux-perf/CMakeLists.txt new file mode 100644 index 000000000..e9882c835 --- /dev/null +++ b/samples/linux-perf/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +project(linux_perf_sample) + +if(NOT CMAKE_HOST_LINUX) + message(FATAL_ERROR "This sample only works on linux") +endif() + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +set(CMAKE_CXX_STANDARD 17) + +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +find_package(WASISDK REQUIRED) + +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +include(CheckPIESupported) + +# AOT and JIT byd default +set(WAMR_BUILD_AOT 1) +set(WAMR_BUILD_INTERP 0) +set(WAMR_BUILD_JIT 1) +# wasm32-wasi +set(WAMR_BUILD_LIBC_BUILTIN 0) +set(WAMR_BUILD_LIBC_WASI 1) +# mvp +set(WAMR_BUILD_BULK_MEMORY 1) +set(WAMR_BUILD_REF_TYPES 1) +set(WAMR_BUILD_SIMD 1) +set(WAMR_BUILD_TAIL_CALL 1) +# trap information +set(WAMR_BUILD_DUMP_CALL_STACK 1) +# linux perf +set(WAMR_BUILD_LINUX_PERF 1) +# +#set(WAMR_BUILD_THREAD_MGR 0) + +# vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib SHARED ${WAMR_RUNTIME_LIB_SOURCE}) +target_include_directories(vmlib INTERFACE ${WAMR_ROOT_DIR}/core/iwasm/include) +target_link_libraries (vmlib ${LLVM_AVAILABLE_LIBS} -lm -ldl) + +################ host ################ +add_executable(${PROJECT_NAME} host/demo.c) +target_link_libraries(${PROJECT_NAME} vmlib) + +################ aot + wasm ################ +include(ExternalProject) +ExternalProject_Add(wasm + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wasm" + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/wasm -B build + -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN} + BUILD_COMMAND ${CMAKE_COMMAND} --build build + INSTALL_COMMAND ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR} +) \ No newline at end of file diff --git a/samples/linux-perf/README.md b/samples/linux-perf/README.md new file mode 100644 index 000000000..5a8dc578f --- /dev/null +++ b/samples/linux-perf/README.md @@ -0,0 +1,90 @@ +# linux perf sample introduction + +This is a sample to show how to use the Linux perf tool to profile the execution of a WebAssembly application. And how to use the [Flamegraph](https://www.brendangregg.com/flamegraphs.html) tool to visualize the profiling result. + +## Build and run the sample + +There are two Wasm modules and their instance will be created and run in the sample. [The first module](./wasm/fib.c) is a simple Wasm module that calculates the Fibonacci number. [The second module](./wasm/ackermann.c) is a simple Wasm module that execute the Ackermann function. The target is enable to profile the execution of both two modules separately. + +```bash +$ cmake -S . -B build +$ cmake --build build +``` + +### Profile the execution + +```bash +$ cd build +$ perf record -k mono -g --output=perf.data -- ./linux_perf_sample +``` + +Enable to use `perf report --stdio` to do a quick analysis of the profiling result. + +### Visualize the profiling result + +Need to download Flamegraph tool from [Flamegraph](https://github.com/brendangregg/FlameGraph/releases/tag/v1.0) firstly. + +```bash +$ perf script > out.perf +$ ./FlameGraph/stackcollapse-perf.pl out.perf > out.folded +$ ./FlameGraph/flamegraph.pl out.folded > perf.svg +``` + +In this result, you'll see two modules's profiling result and all wasm functions are named as "aot_func#N" which is a little hard to distinguish. + +![perf.png](./pics/perf.png) + +### Separate profiling result + +[process_folded_data.py](../../test-tools/flame-graph-helper/process_folded_data.py) is a script can a) translate "aot_func#N" into its original function name in name sections, b) separate the profiling result of different modules. + +In this sample, we want to separate `fib` and `ackermann` profiling data from _out.folded_. In [demo](host/demo.c), we decide to name the module of `fib1.wasm` as `fib2` and the module of `ackermann1.wasm` as `ackermann2`. + +```bash +$ python process_folded_data.py --wabt_home /opt/wabt --wasm_names fib2=./fib1.wasm,ackermann2=./ackermann1.wasm out.folded +-> write into out.fib2.translated +-> write into out.ackermann2.translated +-> write into out.translated +``` + +More scenarios: + +if only using one wasm during profiling, the script can be used like this: + +```bash +$ python process_folded_data.py --wabt_home /opt/wabt --wasm --folded +``` + +if only using one wasm during profiling and specify the module name via APIs, the script can be used like this: + +```bash +$ python process_folded_data.py --wabt_home /opt/wabt --wasm_names = --folded +``` + +if only using one wasm during profiling and specify the module name, which is same with the basename of wasm file, via APIs, the script can be used like this: + +```bash +$ python process_folded_data.py --wabt_home /opt/wabt --wasm --folded +``` + +if using multiple wasm during profiling and specify module names, which are same with basename of wasm files, via APIs, the script can be used like this: + +```bash +$ python process_folded_data.py --wabt_home /opt/wabt --wasm --wasm --wasm --folded +``` + +if using multiple wasm during profiling and specify module names via APIs, the script can be used like this: + +```bash +$ python process_folded_data.py --wabt_home /opt/wabt --wasm_names =,=,= --folded +``` + +Now we have two flame-graphs for two wasm modules: + +![fib.svg](./pics/perf.fib.svg) + +![ackermann.svg](./pics/perf.ackermann.svg) + +## Reference + +- [perf_tune](../../doc/perf_tune.md) diff --git a/samples/linux-perf/cmake/FindWAMRC.cmake b/samples/linux-perf/cmake/FindWAMRC.cmake new file mode 100644 index 000000000..586263edd --- /dev/null +++ b/samples/linux-perf/cmake/FindWAMRC.cmake @@ -0,0 +1,14 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(FindPackageHandleStandardArgs) + +find_file(WAMRC_BIN + NAMES wamrc + DOC "search wamrc" + HINTS ${CMAKE_CURRENT_SOURCE_DIR}/../../../wamr-compiler/build + REQUIRED +) + +find_package_handle_standard_args(WAMRC REQUIRED_VARS WAMRC_BIN) +mark_as_advanced(WAMRC_BIN) \ No newline at end of file diff --git a/samples/linux-perf/cmake/FindWASISDK.cmake b/samples/linux-perf/cmake/FindWASISDK.cmake new file mode 100644 index 000000000..5cdfea41e --- /dev/null +++ b/samples/linux-perf/cmake/FindWASISDK.cmake @@ -0,0 +1,23 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +include(FindPackageHandleStandardArgs) + +file(GLOB WASISDK_SEARCH_PATH "/opt/wasi-sdk-*") +find_path(WASISDK_HOME + NAMES share/wasi-sysroot + PATHS ${WASISDK_SEARCH_PATH} + NO_DEFAULT_PATH + REQUIRED +) + +string(REGEX MATCH [0-9]+\.[0-9]+\.*[0-9]* WASISDK_VERSION ${WASISDK_HOME}) + +find_package_handle_standard_args(WASISDK REQUIRED_VARS WASISDK_HOME VERSION_VAR WASISDK_VERSION) + +if(WASISDK_FOUND) + set(WASISDK_CC_COMMAND ${WASISDK_HOME}/bin/clang) + set(WASISDK_CXX_COMMAND ${WASISDK_HOME}/bin/clang++) + set(WASISDK_TOOLCHAIN ${WASISDK_HOME}/share/cmake/wasi-sdk.cmake) + set(WASISDK_SYSROOT ${WASISDK_HOME}/share/wasi-sysroot) +endif() diff --git a/samples/linux-perf/host/demo.c b/samples/linux-perf/host/demo.c new file mode 100644 index 000000000..8ea446ed4 --- /dev/null +++ b/samples/linux-perf/host/demo.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +/* return a copy of the file stem of a file path */ +static own char * +stem(const char *file_path) +{ + char *base_name = basename(file_path); + char *s = strdup(base_name); + char *dot = strchr(s, '.'); + assert(dot); + *dot = '\0'; + return s; +} + +static void +guest_i32_to_wasm_i32_array(int *args, unsigned argc, wasm_val_t *data, + unsigned datac) +{ + for (unsigned i = 0; i < argc && i < datac; i++) { + memset(&data[i], 0, sizeof(wasm_val_t)); + data[i].kind = WASM_I32; + data[i].of.i32 = args[i]; + } +} + +int +load_run_wasm_file(wasm_engine_t *engine, const char *file_path, int *args, + unsigned argc) +{ + wasm_store_t *store = wasm_store_new(engine); + // Load binary. + printf("Loading binary...\n"); + FILE *file = fopen(file_path, "rb"); + assert(file); + + int ret = fseek(file, 0L, SEEK_END); + assert(ret == 0); + + long file_size = ftell(file); + assert(file_size != -1); + + ret = fseek(file, 0L, SEEK_SET); + assert(ret == 0); + + wasm_byte_vec_t binary = { 0 }; + wasm_byte_vec_new_uninitialized(&binary, file_size); + + size_t nread = fread(binary.data, file_size, 1, file); + fclose(file); + + // Compile. + printf("Compiling module...\n"); + + // Use its file name as the module name + char *file_name = stem(file_path); + assert(file_name); + + LoadArgs load_args = { 0 }; + load_args.name = file_name; + own wasm_module_t *module = wasm_module_new_ex(store, &binary, &load_args); + wasm_byte_vec_delete(&binary); + assert(module); + + // Use export type to find the function index to call later + wasm_exporttype_vec_t export_types = { 0 }; + wasm_module_exports(module, &export_types); + int func_to_call = -1; + for (unsigned i = 0; i < export_types.num_elems; i++) { + const wasm_name_t *name = wasm_exporttype_name(export_types.data[i]); + if (strncmp(name->data, "run", 3) == 0) { + func_to_call = i; + break; + } + } + assert(func_to_call != -1); + + // Instantiate. + printf("Instantiating module...\n"); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + own wasm_instance_t *instance = wasm_instance_new_with_args( + store, module, &imports, NULL, 16 * 1024 * 1024, 1 * 1024 * 1024); + assert(instance); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + assert(exports.size); + + assert(wasm_extern_kind(exports.data[func_to_call]) == WASM_EXTERN_FUNC); + const wasm_func_t *run_func = + wasm_extern_as_func(exports.data[func_to_call]); + assert(run_func); + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + wasm_val_t as[4] = { 0 }; + guest_i32_to_wasm_i32_array(args, argc, as, 4); + + wasm_val_vec_t params = WASM_ARRAY_VEC(as); + wasm_val_t rs[1] = { WASM_I32_VAL(0) }; + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + wasm_trap_t *trap = wasm_func_call(run_func, ¶ms, &results); + assert(!trap); + + wasm_extern_vec_delete(&exports); + free(file_name); + wasm_store_delete(store); + + { + nread = nread; + ret = ret; + trap = trap; + } + return 0; +} + +void * +load_run_fib_wasm(void *arg) +{ + wasm_engine_t *engine = (wasm_engine_t *)arg; + int args[] = { 40 }; + load_run_wasm_file(engine, "./fib1.wasm", args, 1); + return NULL; +} + +void * +load_run_fib_aot(void *arg) +{ + wasm_engine_t *engine = (wasm_engine_t *)arg; + int args[] = { 40 }; + load_run_wasm_file(engine, "./fib2.aot", args, 1); + return NULL; +} + +void * +load_run_ackermann_wasm(void *arg) +{ + wasm_engine_t *engine = (wasm_engine_t *)arg; + int args[] = { 3, 12 }; + load_run_wasm_file(engine, "./ackermann1.wasm", args, 2); + return NULL; +} + +void * +load_run_ackermann_aot(void *arg) +{ + wasm_engine_t *engine = (wasm_engine_t *)arg; + int args[] = { 3, 12 }; + load_run_wasm_file(engine, "./ackermann2.aot", args, 2); + return NULL; +} + +int +main(int argc, const char *argv[]) +{ + // Initialize. + printf("Initializing...\n"); + wasm_config_t *config = wasm_config_new(); + wasm_config_set_linux_perf_opt(config, true); + wasm_engine_t *engine = wasm_engine_new_with_config(config); + + pthread_t tid[4] = { 0 }; + /* FIXME: uncomment when it is able to run two modules with llvm-jit */ + // pthread_create(&tid[0], NULL, load_run_fib_wasm, (void *)engine); + // pthread_create(&tid[2], NULL, load_run_ackermann_wasm, (void *)engine); + + pthread_create(&tid[1], NULL, load_run_fib_aot, (void *)engine); + pthread_create(&tid[3], NULL, load_run_ackermann_aot, (void *)engine); + + for (unsigned i = 0; i < sizeof(tid) / sizeof(tid[0]); i++) + pthread_join(tid[i], NULL); + + // Shut down. + printf("Shutting down...\n"); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/linux-perf/pics/perf.ackermann.svg b/samples/linux-perf/pics/perf.ackermann.svg new file mode 100644 index 000000000..c2e1d8747 --- /dev/null +++ b/samples/linux-perf/pics/perf.ackermann.svg @@ -0,0 +1,1349 @@ + + + + + + + + + + + + + + +Flame Graph + +Reset Zoom +Search +ic + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +load_run_wasm_file (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +invoke_ii_i (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +load_run_ackermann_aot (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] run (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +wasm_runtime_call_wasm (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +all (11,485,868,643 samples, 100%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +aot_call_function (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +linux_perf_samp (11,485,868,643 samples, 100.00%) +linux_perf_samp + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +wasm_func_call (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +invoke_native_with_hw_bound_check (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +start_thread (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (11,484,299,081 samples, 99.99%) +[Wasm] [ackermann2] ackermann + + +[Wasm] [ackermann2] ackermann (1,569,562 samples, 0.01%) + + + + diff --git a/samples/linux-perf/pics/perf.fib.svg b/samples/linux-perf/pics/perf.fib.svg new file mode 100644 index 000000000..a1db059a7 --- /dev/null +++ b/samples/linux-perf/pics/perf.fib.svg @@ -0,0 +1,605 @@ + + + + + + + + + + + + + + +Flame Graph + +Reset Zoom +Search +ic + + + +[Wasm] [fib2] fibonacci (1,321,095,222 samples, 93.80%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (382,407,564 samples, 27.15%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (15,340,273 samples, 1.09%) + + + +[Wasm] [fib2] fibonacci (1,359,552,763 samples, 96.53%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,408,481,525 samples, 100.00%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (27,274,310 samples, 1.94%) +[.. + + +[Wasm] [fib2] fibonacci (62,450,767 samples, 4.43%) +[Wasm.. + + +[Wasm] [fib2] fibonacci (1,408,481,525 samples, 100.00%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,388,674,508 samples, 98.59%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,170,751,868 samples, 83.12%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,408,481,525 samples, 100.00%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (120,820,158 samples, 8.58%) +[Wasm] [fib2.. + + +invoke_i_i (1,408,481,525 samples, 100.00%) +invoke_i_i + + +[Wasm] [fib2] fibonacci (1,375,872,224 samples, 97.68%) +[Wasm] [fib2] fibonacci + + +load_run_wasm_file (1,408,481,525 samples, 100.00%) +load_run_wasm_file + + +load_run_fib_aot (1,408,481,525 samples, 100.00%) +load_run_fib_aot + + +[Wasm] [fib2] run (1,408,481,525 samples, 100.00%) +[Wasm] [fib2] run + + +[Wasm] [fib2] fibonacci (42,420,273 samples, 3.01%) +[Wa.. + + +[Wasm] [fib2] fibonacci (1,266,323,684 samples, 89.91%) +[Wasm] [fib2] fibonacci + + +linux_perf_samp (1,408,481,525 samples, 100.00%) +linux_perf_samp + + +[Wasm] [fib2] fibonacci (280,259,464 samples, 19.90%) +[Wasm] [fib2] fibonacci + + +start_thread (1,408,481,525 samples, 100.00%) +start_thread + + +[Wasm] [fib2] fibonacci (2,334,521 samples, 0.17%) + + + +[Wasm] [fib2] fibonacci (666,394,609 samples, 47.31%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (943,121,736 samples, 66.96%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,169,581 samples, 0.08%) + + + +[Wasm] [fib2] fibonacci (1,169,581 samples, 0.08%) + + + +[Wasm] [fib2] fibonacci (194,755,877 samples, 13.83%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,406,148,966 samples, 99.83%) +[Wasm] [fib2] fibonacci + + +all (1,408,481,525 samples, 100%) + + + +wasm_func_call (1,408,481,525 samples, 100.00%) +wasm_func_call + + +[Wasm] [fib2] fibonacci (5,943,602 samples, 0.42%) + + + +[Wasm] [fib2] fibonacci (1,408,481,525 samples, 100.00%) +[Wasm] [fib2] fibonacci + + +wasm_runtime_call_wasm (1,408,481,525 samples, 100.00%) +wasm_runtime_call_wasm + + +[Wasm] [fib2] fibonacci (1,401,486,191 samples, 99.50%) +[Wasm] [fib2] fibonacci + + +aot_call_function (1,408,481,525 samples, 100.00%) +aot_call_function + + +[Wasm] [fib2] fibonacci (531,941,563 samples, 37.77%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,406,148,966 samples, 99.83%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,061,055,435 samples, 75.33%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,408,481,525 samples, 100.00%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (1,403,816,880 samples, 99.67%) +[Wasm] [fib2] fibonacci + + +[Wasm] [fib2] fibonacci (800,646,766 samples, 56.84%) +[Wasm] [fib2] fibonacci + + +invoke_native_with_hw_bound_check (1,408,481,525 samples, 100.00%) +invoke_native_with_hw_bound_check + + + diff --git a/samples/linux-perf/pics/perf.png b/samples/linux-perf/pics/perf.png new file mode 100755 index 000000000..fc4c0930f Binary files /dev/null and b/samples/linux-perf/pics/perf.png differ diff --git a/samples/linux-perf/wasm/CMakeLists.txt b/samples/linux-perf/wasm/CMakeLists.txt new file mode 100644 index 000000000..8d36e28df --- /dev/null +++ b/samples/linux-perf/wasm/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +project(linux_perf_sample_wasm) + +include(CMakePrintHelpers) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake) +find_package(WAMRC REQUIRED) + +################ wasm ################ +add_executable(fib_wasm fib.c) +set_target_properties(fib_wasm PROPERTIES SUFFIX .wasm) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fib_wasm.wasm DESTINATION . RENAME fib1.wasm) + +add_executable(ackermann_wasm ackermann.c) +set_target_properties(ackermann_wasm PROPERTIES SUFFIX .wasm) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ackermann_wasm.wasm DESTINATION . RENAME ackermann1.wasm) + + +################ aot ################ +add_custom_target(fib_aot + ALL + COMMAND ${WAMRC_BIN} --enable-linux-perf -o fib2.aot fib_wasm.wasm + DEPENDS fib_wasm + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fib2.aot DESTINATION .) + +add_custom_target(ackermann_aot + ALL + COMMAND ${WAMRC_BIN} --enable-linux-perf -o ackermann2.aot ackermann_wasm.wasm + DEPENDS ackermann_wasm + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ackermann2.aot DESTINATION .) diff --git a/samples/linux-perf/wasm/ackermann.c b/samples/linux-perf/wasm/ackermann.c new file mode 100644 index 000000000..d6eb4346f --- /dev/null +++ b/samples/linux-perf/wasm/ackermann.c @@ -0,0 +1,38 @@ +#include + +// Ackermann function +unsigned long +ackermann(unsigned long m, unsigned long n) +{ + if (m == 0) { + return n + 1; + } + else if (n == 0) { + return ackermann(m - 1, 1); + } + else { + return ackermann(m - 1, ackermann(m, n - 1)); + } +} + +__attribute__((export_name("run"))) int +run(int m, int n) +{ + int result = ackermann(m, n); + printf("ackermann(%d, %d)=%d\n", m, n, result); + return result; +} + +int +main() +{ + unsigned long m, n, result; + + // Example usage: + m = 3; + n = 2; + result = ackermann(m, n); + printf("Ackermann(%lu, %lu) = %lu\n", m, n, result); + + return 0; +} diff --git a/samples/linux-perf/wasm/fib.c b/samples/linux-perf/wasm/fib.c new file mode 100644 index 000000000..cb928f65d --- /dev/null +++ b/samples/linux-perf/wasm/fib.c @@ -0,0 +1,32 @@ +#include +#include + +int +fibonacci(int n) +{ + if (n <= 0) + return 0; + + if (n == 1) + return 1; + + return fibonacci(n - 1) + fibonacci(n - 2); +} + +__attribute__((export_name("run"))) int +run(int n) +{ + int result = fibonacci(n); + printf("fibonacci(%d)=%d\n", n, result); + return result; +} + +int +main(int argc, char **argv) +{ + int n = atoi(argv[1]); + + printf("fibonacci(%d)=%d\n", n, fibonacci(n)); + + return 0; +} diff --git a/test-tools/addr2line/addr2line.py b/test-tools/addr2line/addr2line.py index 4502d5fec..421b0bdb2 100644 --- a/test-tools/addr2line/addr2line.py +++ b/test-tools/addr2line/addr2line.py @@ -43,6 +43,28 @@ For example, there is a call-stack dump: """ +def locate_sourceMappingURL_section(wasm_objdump: Path, wasm_file: Path) -> bool: + """ + Figure out if the wasm file has a sourceMappingURL section. + """ + cmd = f"{wasm_objdump} -h {wasm_file}" + p = subprocess.run( + shlex.split(cmd), + check=True, + capture_output=True, + text=True, + universal_newlines=True, + ) + outputs = p.stdout.split(os.linesep) + + for line in outputs: + line = line.strip() + if "sourceMappingURL" in line: + return True + + return False + + def get_code_section_start(wasm_objdump: Path, wasm_file: Path) -> int: """ Find the start offset of Code section in a wasm file. @@ -62,15 +84,6 @@ def get_code_section_start(wasm_objdump: Path, wasm_file: Path) -> int: ) outputs = p.stdout.split(os.linesep) - # if there is no .debug section, return -1 - for line in outputs: - line = line.strip() - if ".debug_info" in line: - break - else: - print(f"No .debug_info section found {wasm_file}") - return -1 - for line in outputs: line = line.strip() if "Code" in line: @@ -79,7 +92,7 @@ def get_code_section_start(wasm_objdump: Path, wasm_file: Path) -> int: return -1 -def get_line_info_from_function_addr( +def get_line_info_from_function_addr_dwarf( dwarf_dump: Path, wasm_file: Path, offset: int ) -> tuple[str, str, str, str]: """ @@ -126,7 +139,7 @@ def get_dwarf_tag_value(tag: str, line: str) -> str: return m.groups()[0] -def get_line_info_from_function_name( +def get_line_info_from_function_name_dwarf( dwarf_dump: Path, wasm_file: Path, function_name: str ) -> tuple[str, str, str]: """ @@ -160,6 +173,51 @@ def get_line_info_from_function_name( return (function_name, function_file, function_line) +def get_line_info_from_function_addr_sourcemapping( + emsymbolizer: Path, wasm_file: Path, offset: int +) -> tuple[str, str, str, str]: + """ + Find the location info of a given offset in a wasm file which is compiled with emcc. + + {emsymbolizer} {wasm_file} {offset of file} + + there usually are two lines: + ?? + relative path to source file:line:column + """ + debug_info_source = wasm_file.with_name(f"{wasm_file.name}.map") + cmd = f"{emsymbolizer} -t code -f {debug_info_source} {wasm_file} {offset}" + p = subprocess.run( + shlex.split(cmd), + check=False, + capture_output=True, + text=True, + universal_newlines=True, + cwd=Path.cwd(), + ) + outputs = p.stdout.split(os.linesep) + + function_name, function_file = "", "unknown" + function_line, function_column = "?", "?" + + for line in outputs: + line = line.strip() + + if not line: + continue + + m = re.match("(.*):(\d+):(\d+)", line) + if m: + function_file, function_line, function_column = m.groups() + continue + else: + # it's always ??, not sure about that + if "??" != line: + function_name = line + + return (function_name, function_file, function_line, function_column) + + def parse_line_info(line_info: str) -> tuple[str, str, str]: """ line_info -> [file, line, column] @@ -178,9 +236,13 @@ def parse_call_stack_line(line: str) -> tuple[str, str, str]: #00: 0x0a04 - $f18 => (00, 0x0a04, $f18) Old format: #00 $f18 => (00, _, $f18) + Text format (-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1 -DWAMR_BUILD_CUSTOM_NAME_SECTION=1): + #02: 0x0200 - a => (02, 0x0200, a) + _start (always): + #05: 0x011f - _start => (05, 0x011f, _start) """ - # New format + # New format and Text format and _start PATTERN = r"#([0-9]+): 0x([0-9a-f]+) - (\S+)" m = re.match(PATTERN, line) if m is not None: @@ -246,6 +308,7 @@ def main(): action="store_true", help="use call stack without addresses or from fast interpreter mode", ) + parser.add_argument("--emsdk", type=Path, help="path to emsdk") args = parser.parse_args() wasm_objdump = args.wabt.joinpath("bin/wasm-objdump") @@ -257,12 +320,20 @@ def main(): llvm_cxxfilt = args.wasi_sdk.joinpath("bin/llvm-cxxfilt") assert llvm_cxxfilt.exists() + emcc_production = locate_sourceMappingURL_section(wasm_objdump, args.wasm_file) + if emcc_production: + if args.emsdk is None: + print("Please provide the path to emsdk via --emsdk") + return -1 + + emsymbolizer = args.emsdk.joinpath("upstream/emscripten/emsymbolizer") + assert emsymbolizer.exists() + code_section_start = get_code_section_start(wasm_objdump, args.wasm_file) if code_section_start == -1: return -1 - if args.no_addr: - function_index_to_name = parse_module_functions(wasm_objdump, args.wasm_file) + function_index_to_name = parse_module_functions(wasm_objdump, args.wasm_file) assert args.call_stack_file.exists() with open(args.call_stack_file, "rt", encoding="ascii") as f: @@ -272,38 +343,68 @@ def main(): continue splitted = parse_call_stack_line(line) - assert splitted is not None + if splitted is None: + print(f"{line}") + continue _, offset, index = splitted - if not index.startswith("$f"): # E.g. _start - print(f"{i}: {index}") - continue - index = index[2:] - if args.no_addr: + # FIXME: w/ emcc production + if not index.startswith("$f"): # E.g. _start or Text format + print(f"{i}: {index}") + continue + index = index[2:] + if index not in function_index_to_name: print(f"{i}: {line}") continue - line_info = get_line_info_from_function_name( - llvm_dwarf_dump, args.wasm_file, function_index_to_name[index] - ) + if not emcc_production: + _, function_file, function_line = ( + get_line_info_from_function_name_dwarf( + llvm_dwarf_dump, + args.wasm_file, + function_index_to_name[index], + ) + ) + else: + _, function_file, function_line = _, "unknown", "?" - _, funciton_file, function_line = line_info function_name = demangle(llvm_cxxfilt, function_index_to_name[index]) print(f"{i}: {function_name}") - print(f"\tat {funciton_file}:{function_line}") + print(f"\tat {function_file}:{function_line}") else: offset = int(offset, 16) + # match the algorithm in wasm_interp_create_call_stack() + # either a *offset* to *code* section start + # or a *offset* in a file + assert offset > code_section_start offset = offset - code_section_start - line_info = get_line_info_from_function_addr( - llvm_dwarf_dump, args.wasm_file, offset - ) - function_name, funciton_file, function_line, function_column = line_info + if emcc_production: + function_name, function_file, function_line, function_column = ( + get_line_info_from_function_addr_sourcemapping( + emsymbolizer, args.wasm_file, offset + ) + ) + else: + function_name, function_file, function_line, function_column = ( + get_line_info_from_function_addr_dwarf( + llvm_dwarf_dump, args.wasm_file, offset + ) + ) + + # if can't parse function_name, use name section or + if function_name == "": + if index.startswith("$f"): + function_name = function_index_to_name.get(index[2:], index) + else: + function_name = index + function_name = demangle(llvm_cxxfilt, function_name) + print(f"{i}: {function_name}") - print(f"\tat {funciton_file}:{function_line}:{function_column}") + print(f"\tat {function_file}:{function_line}:{function_column}") return 0 diff --git a/test-tools/flame-graph-helper/.gitignore b/test-tools/flame-graph-helper/.gitignore new file mode 100644 index 000000000..b5ddc69ff --- /dev/null +++ b/test-tools/flame-graph-helper/.gitignore @@ -0,0 +1,2 @@ +*.* +!*.py \ No newline at end of file diff --git a/test-tools/flame-graph-helper/process_folded_data.py b/test-tools/flame-graph-helper/process_folded_data.py new file mode 100644 index 000000000..e4650fe25 --- /dev/null +++ b/test-tools/flame-graph-helper/process_folded_data.py @@ -0,0 +1,325 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +""" +It is used to process *out.folded* file generated by [FlameGraph](https://github.com/brendangregg/FlameGraph). + +- translate jitted function names, which are in a form like `aot_func#N` or `[module name]#aot_func#N`, into corresponding names in a name section in .wasm +- divide the translated functions into different modules if the module name is specified in the symbol + +Usage: + +After +``` bash +# collect profiling data in perf.data + +$ perf script -i perf.data > out.perf + +$ ./FlameGraph/stackcollapse-perf.pl out.perf > out.folded +``` + +Use this script to translate the function names in out.folded + +``` +$ python translate_wasm_function_name.py --wabt_home --folded out.folded <.wasm> +# out.folded -> out.folded.translated +``` + +""" + +import argparse +import os +from pathlib import Path +import re +import shlex +import subprocess +from typing import Dict, List + + +# parse arguments like "foo=bar,fiz=biz" into a dictatory {foo:bar,fiz=biz} +class ParseKVArgs(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, dict()) + for value in values.split(","): + k, v = value.split("=") + getattr(namespace, self.dest)[k] = v + + +def calculate_import_function_count( + wasm_objdump_bin: Path, module_names: Dict[str, Path] +) -> Dict[str, int]: + """ + for every wasm file in , calculate the number of functions in the import section. + + using " -j Import -x " + """ + + assert wasm_objdump_bin.exists() + + import_function_counts = {} + for module_name, wasm_path in module_names.items(): + assert wasm_path.exists() + command = f"{wasm_objdump_bin} -j Import -x {wasm_path}" + p = subprocess.run( + shlex.split(command), + capture_output=True, + check=False, + text=True, + universal_newlines=True, + ) + + if p.stderr: + print("No content in import section") + import_function_counts[module_name] = 0 + continue + + import_function_count = 0 + for line in p.stdout.split(os.linesep): + line = line.strip() + + if not line: + continue + + if not " func" in line: + continue + + m = re.search(r"^-\s+func", line) + assert m + + import_function_count += 1 + + # print(f"! there are {import_function_count} import function in {module_name}") + import_function_counts[module_name] = import_function_count + + return import_function_counts + + +def collect_name_section_content( + wasm_objdump_bin: Path, module_names: Dict[str, Path] +) -> Dict[str, Dict[int, str]]: + """ + for every wasm file in , get the content of name section. + + execute "wasm_objdump_bin -j name -x wasm_file" + """ + assert wasm_objdump_bin.exists() + + name_sections = {} + for module_name, wasm_path in module_names.items(): + assert wasm_path.exists() + command = f"{wasm_objdump_bin} -j name -x {wasm_path}" + p = subprocess.run( + shlex.split(command), + capture_output=True, + check=False, + text=True, + universal_newlines=True, + ) + + if p.stderr: + print("No content in name section") + name_sections[module_name] = {} + continue + + name_section = {} + for line in p.stdout.split(os.linesep): + line = line.strip() + + if not line: + continue + + if not " func" in line: + continue + + # - func[N] <__imported_wasi_snapshot_preview1_fd_close> + m = re.match(r"- func\[(\d+)\] <(.+)>", line) + assert m + + func_index, func_name = m.groups() + name_section.update({int(func_index): func_name}) + + name_sections[module_name] = name_section + + return name_sections + + +def is_stack_check_mode(folded: Path) -> bool: + """ + check if there is a function name looks like "aot_func_internal#N", it means that WAMR adds a stack check function before the original function. + """ + with open(folded, "rt", encoding="utf-8") as f: + for line in f: + line = line.strip() + if "aot_func_internal" in line: + return True + return False + + +def replace_function_name( + import_function_counts: Dict[str, int], + name_sections: Dict[str, Dict[int, str]], + folded_in: Path, + module_names: Dict[str, Path], +) -> None: + """ + read content in . every line contains symbols which are separated by ";". + + Usually, all jitted functions are in the form of "aot_func#N". N is its function index. Use the index to find the corresponding function name in the name section. + + if there is a function name looks like "aot_func_internal#N", it means that WAMR adds a stack check function before the original function. + In this case, "aot_func#N" should be translated with "_precheck" as a suffix and "aot_func_internal#N" should be treated as the original one + """ + + assert folded_in.exists(), f"{folded_in} doesn't exist" + + stack_check_mode = is_stack_check_mode(folded_in) + + # every wasm has a translated out.folded, like out..folded.translated + folded_out_files = {} + for module_name in module_names.keys(): + wasm_folded_out_path = folded_in.with_suffix(f".{module_name}.translated") + print(f"-> write into {wasm_folded_out_path}") + folded_out_files[module_name] = wasm_folded_out_path.open( + "wt", encoding="utf-8" + ) + # Plus a default translated out.folded + default_folded_out_path = folded_in.with_suffix(".translated") + print(f"-> write into {default_folded_out_path}") + default_folded_out = default_folded_out_path.open("wt", encoding="utf-8") + + with folded_in.open("rt", encoding="utf-8") as f_in: + for line in f_in: + line = line.strip() + + m = re.match(r"(.*) (\d+)", line) + assert m + syms, samples = m.groups() + + new_line = [] + last_function_module_name = "" + for sym in syms.split(";"): + if not "aot_func" in sym: + new_line.append(sym) + continue + + # [module_name]#aot_func#N or aot_func#N + splitted = sym.split("#") + module_name = "" if splitted[0] == "aot_func" else splitted[0] + # remove [ and ] + module_name = module_name[1:-1] + + if len(module_name) == 0 and len(module_names) > 1: + raise RuntimeError( + f"❌ {sym} doesn't have a module name, but there are multiple wasm files" + ) + + if not module_name in module_names: + raise RuntimeError( + f"❌ can't find corresponds wasm file for {module_name}" + ) + + last_function_module_name = module_name + + func_idx = int(splitted[-1]) + # adjust index + func_idx = func_idx + import_function_counts[module_name] + + # print(f"🔍 {module_name} {splitted[1]} {func_idx}") + + if func_idx in name_sections[module_name]: + if len(module_name) > 0: + wasm_func_name = f"[Wasm] [{module_name}] {name_sections[module_name][func_idx]}" + else: + wasm_func_name = ( + f"[Wasm] {name_sections[module_name][func_idx]}" + ) + else: + if len(module_name) > 0: + wasm_func_name = f"[Wasm] [{module_name}] func[{func_idx}]" + else: + wasm_func_name = f"[Wasm] func[{func_idx}]" + + if stack_check_mode: + # aot_func_internal -> xxx + # aot_func --> xxx_precheck + if "aot_func" == splitted[1]: + wasm_func_name += "_precheck" + + new_line.append(wasm_func_name) + + line = ";".join(new_line) + line += f" {samples}" + + # always write into the default output + default_folded_out.write(line + os.linesep) + # based on the module name of last function, write into the corresponding output + if len(last_function_module_name) > 0: + folded_out_files[last_function_module_name].write(line + os.linesep) + + default_folded_out.close() + for f in folded_out_files.values(): + f.close() + + +def main(wabt_home: str, folded: str, module_names: Dict[str, Path]) -> None: + wabt_home = Path(wabt_home) + assert wabt_home.exists() + + folded = Path(folded) + assert folded.exists() + + wasm_objdump_bin = wabt_home.joinpath("bin", "wasm-objdump") + import_function_counts = calculate_import_function_count( + wasm_objdump_bin, module_names + ) + + name_sections = collect_name_section_content(wasm_objdump_bin, module_names) + + replace_function_name(import_function_counts, name_sections, folded, module_names) + + +if __name__ == "__main__": + argparse = argparse.ArgumentParser() + argparse.add_argument( + "--wabt_home", required=True, help="wabt home, like /opt/wabt-1.0.33" + ) + argparse.add_argument( + "--wasm", + action="append", + default=[], + help="wasm files for profiling before. like --wasm apple.wasm --wasm banana.wasm", + ) + argparse.add_argument( + "--wasm_names", + action=ParseKVArgs, + default={}, + metavar="module_name=wasm_file, ...", + help="multiple wasm files and their module names, like a=apple.wasm,b=banana.wasm,c=cake.wasm", + ) + argparse.add_argument( + "folded_file", + help="a out.folded generated by flamegraph/stackcollapse-perf.pl", + ) + + args = argparse.parse_args() + + if not args.wasm and not args.wasm_names: + print("Please specify wasm files with either --wasm or --wasm_names") + exit(1) + + # - only one wasm file. And there is no [module name] in out.folded + # - multiple wasm files. via `--wasm X --wasm Y --wasm Z`. And there is [module name] in out.folded. use the basename of wasm as the module name + # - multiple wasm files. via `--wasm_names X=x,Y=y,Z=z`. And there is [module name] in out.folded. use the specified module name + module_names = {} + if args.wasm_names: + for name, wasm_path in args.wasm_names.items(): + module_names[name] = Path(wasm_path) + else: + # use the basename of wasm as the module name + for wasm in args.wasm: + wasm_path = Path(wasm) + module_names[wasm_path.stem] = wasm_path + + main(args.wabt_home, args.folded_file, module_names) diff --git a/test-tools/trans-jitted-func-name/trans_wasm_func_name.py b/test-tools/trans-jitted-func-name/trans_wasm_func_name.py deleted file mode 100644 index 0206fc287..000000000 --- a/test-tools/trans-jitted-func-name/trans_wasm_func_name.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# -""" -It is used to translate jitted functions' names(in out.folded) to coorespond name in name section in .wasm - -Usage: - -After -``` -$ perf script -i perf.data > out.perf - -# fold call stacks -$ ./FlameGraph/stackcollapse-perf.pl out.perf > out.folded -``` - -Add a step: -``` -# translate jitted functions' names -$ python translate_wasm_function_name.py --wabt_home --folded out.folded <.wasm> -# out.folded -> out.folded.translated -$ ls out.folded.translated -``` - -Then -``` -# generate flamegraph -$ ./FlameGraph/flamegraph.pl out.folded.translated > perf.wasm.svg -``` - -""" - -import argparse -import os -from pathlib import Path -import re -import shlex -import subprocess - - -def preflight_check(wabt_home: Path) -> Path: - """ - if wasm-objdump exists in wabt_home - """ - wasm_objdump_bin = wabt_home.joinpath("bin", "wasm-objdump") - if not wasm_objdump_bin.exists(): - raise RuntimeError(f"wasm-objdump not found in {wabt_home}") - - return wasm_objdump_bin - - -def collect_import_section_content(wasm_objdump_bin: Path, wasm_file: Path) -> dict: - """ - execute "wasm_objdump_bin -j Import -x " and return a dict like {function: X, global: Y, memory: Z, table: N} - """ - assert wasm_objdump_bin.exists() - assert wasm_file.exists() - - command = f"{wasm_objdump_bin} -j Import -x {wasm_file}" - p = subprocess.run( - shlex.split(command), - capture_output=True, - check=False, - text=True, - universal_newlines=True, - ) - - if p.stderr: - print("No content in import section") - return {} - - import_section = {} - for line in p.stdout.split(os.linesep): - line = line.strip() - - if not line: - continue - - if re.search(r"^-\s+func", line): - import_section.update(function=import_section.get("function", 0) + 1) - else: - pass - - assert len(import_section) > 0, "failed to retrive content of import section" - return import_section - - -def collect_name_section_content(wasm_objdump_bin: Path, wasm_file: Path) -> dict: - """ - execute "wasm_objdump_bin -j name -x wasm_file" and store the output in a dict - {1: xxxx, 2: yyyy, 3: zzzz} - """ - assert wasm_objdump_bin.exists() - assert wasm_file.exists() - - command = f"{wasm_objdump_bin} -j name -x {wasm_file}" - p = subprocess.run( - shlex.split(command), - capture_output=True, - check=False, - text=True, - universal_newlines=True, - ) - - if p.stderr: - raise RuntimeError(f"not found name section in {wasm_file}") - - name_section = {} - for line in p.stdout.split(os.linesep): - line = line.strip() - - if not line: - continue - - # - func[0] <__imported_wasi_snapshot_preview1_fd_close> - if line.startswith("- func"): - m = re.match(r"- func\[(\d+)\] <(.+)>", line) - assert m - - func_index, func_name = m.groups() - name_section.update({int(func_index): func_name}) - - assert name_section - return name_section - - -def replace_function_name( - import_section: dict, name_section: dict, folded_in: str, folded_out: str -) -> None: - """ - read content in . each line will be like: - - quiche::BalsaFrame::ProcessHeaders;non-virtual thunk to Envoy::Http::Http1::BalsaParser::MessageDone;Envoy::Http::Http1::ConnectionImpl::onMessageComplete;Envoy::Http::Http1::ConnectionImpl::onMessageCompleteImpl;Envoy::Http::Http1::ServerConnectionImpl::onMessageCompleteBase;Envoy::Http::ConnectionManagerImpl::ActiveStream::decodeHeaders;Envoy::Http::FilterManager::decodeHeaders;virtual thunk to Envoy::Extensions::Common::Wasm::Context::decodeHeaders;proxy_wasm::ContextBase::onRequestHeaders;proxy_wasm::wamr::Wamr::getModuleFunctionImpl;wasm_func_call;wasm_runtime_call_wasm;wasm_call_function;call_wasm_with_hw_bound_check;wasm_interp_call_wasm;llvm_jit_call_func_bytecode;wasm_runtime_invoke_native;push_args_end;aot_func_internal#3302;aot_func_internal#3308;asm_sysvec_apic_timer_interrupt;sysvec_apic_timer_interrupt;__sysvec_apic_timer_interrupt;hrtimer_interrupt;__hrtimer_run_queues;__remove_hrtimer;rb_next 1110899 - - symbol names are spearated by ";" - - if there is a symbol named like "aot_func#XXX" or "aot_func_internal#XXX", it will be replaced with the function name in name section by index - """ - folded_in = Path(folded_in) - assert folded_in.exists() - folded_out = Path(folded_out) - - import_function_count = import_section.get("function", 0) - with folded_in.open("rt", encoding="utf-8") as f_in, folded_out.open( - "wt", encoding="utf-8" - ) as f_out: - precheck_mode = False - for line in f_in: - line = line.strip() - if "aot_func_internal" in line: - precheck_mode = True - - f_in.seek(0) - for line in f_in: - new_line = [] - line = line.strip() - - m = re.match(r"(.*) (\d+)", line) - syms, samples = m.groups() - for sym in syms.split(";"): - m = re.match(r"aot_func(_internal)?#(\d+)", sym) - if not m: - new_line.append(sym) - continue - - func_idx = int(m.groups()[-1]) + import_function_count - if func_idx in name_section: - wasm_func_name = f"[Wasm] {name_section[func_idx]}" - else: - wasm_func_name = ( - f"[Wasm] function[{func_idx + import_function_count}]" - ) - - if precheck_mode: - # aot_func_internal -> xxx - # aot_func --> xxx_precheck - wasm_func_name += "_precheck" if not m.groups()[0] else "" - else: - # aot_func --> xxx - pass - - new_line.append(wasm_func_name) - - line = ";".join(new_line) - line += f" {samples}" - f_out.write(line + os.linesep) - - print(f"⚙️ {folded_in} -> {folded_out}") - - -def main(wabt_home: str, wasm_file: str, folded: str) -> None: - wabt_home = Path(wabt_home) - wasm_file = Path(wasm_file) - - wasm_objdump_bin = preflight_check(wabt_home) - import_section = collect_import_section_content(wasm_objdump_bin, wasm_file) - name_section = collect_name_section_content(wasm_objdump_bin, wasm_file) - - replace_function_name(import_section, name_section, folded, folded + ".translated") - - -if __name__ == "__main__": - argparse = argparse.ArgumentParser() - argparse.add_argument( - "--folded", help="stackcollapse-perf.pl generated, like out.folded" - ) - argparse.add_argument("wasm_file", help="wasm file") - argparse.add_argument("--wabt_home", help="wabt home, like /opt/wabt-1.0.33") - - args = argparse.parse_args() - main(args.wabt_home, args.wasm_file, args.folded) diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 8027abde0..13db47203 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -14,7 +14,7 @@ import time """ The script itself has to be put under the same directory with the "spec". -To run a single non-GC case with interpreter mode: +To run a single non-GC and non-memory64 case with interpreter mode: cd workspace python3 runtest.py --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \ spec/test/core/xxx.wast @@ -22,7 +22,7 @@ To run a single non-GC case with aot mode: cd workspace python3 runtest.py --aot --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \ --aot-compiler wamrc spec/test/core/xxx.wast -To run a single GC case: +To run a single GC case or single memory64 case: cd workspace python3 runtest.py --wast2wasm spec/interpreter/wasm --interpreter iwasm \ --aot-compiler wamrc --gc spec/test/core/xxx.wast @@ -78,6 +78,7 @@ def ignore_the_case( multi_thread_flag=False, simd_flag=False, gc_flag=False, + memory64_flag=False, xip_flag=False, eh_flag=False, qemu_flag=False, @@ -94,7 +95,7 @@ def ignore_the_case( return True if gc_flag: - if case_name in ["type-equivalence", "type-rec", "array_init_elem", "array_init_data"]: + if case_name in ["array_init_elem", "array_init_data"]: return True if sgx_flag: @@ -162,6 +163,7 @@ def test_case( clean_up_flag=True, verbose_flag=True, gc_flag=False, + memory64_flag=False, qemu_flag=False, qemu_firmware="", log="", @@ -169,7 +171,7 @@ def test_case( ): CMD = [sys.executable, "runtest.py"] CMD.append("--wast2wasm") - CMD.append(WAST2WASM_CMD if not gc_flag else SPEC_INTERPRETER_CMD) + CMD.append(WAST2WASM_CMD if not gc_flag and not memory64_flag else SPEC_INTERPRETER_CMD) CMD.append("--interpreter") if sgx_flag: CMD.append(IWASM_SGX_CMD) @@ -217,6 +219,9 @@ def test_case( if gc_flag: CMD.append("--gc") + if memory64_flag: + CMD.append("--memory64") + if log != "": CMD.append("--log-dir") CMD.append(log) @@ -283,6 +288,7 @@ def test_suite( clean_up_flag=True, verbose_flag=True, gc_flag=False, + memory64_flag=False, parl_flag=False, qemu_flag=False, qemu_firmware="", @@ -325,6 +331,7 @@ def test_suite( multi_thread_flag, simd_flag, gc_flag, + memory64_flag, xip_flag, eh_flag, qemu_flag, @@ -357,6 +364,7 @@ def test_suite( clean_up_flag, verbose_flag, gc_flag, + memory64_flag, qemu_flag, qemu_firmware, log, @@ -382,6 +390,7 @@ def test_suite( else: print(f"----- Run the whole spec test suite -----") for case_path in case_list: + print(case_path) try: test_case( str(case_path), @@ -396,6 +405,7 @@ def test_suite( clean_up_flag, verbose_flag, gc_flag, + memory64_flag, qemu_flag, qemu_firmware, log, @@ -521,6 +531,13 @@ def main(): dest="gc_flag", help="Running with GC feature", ) + parser.add_argument( + "--memory64", + action="store_true", + default=False, + dest="memory64_flag", + help="Running with memory64 feature", + ) parser.add_argument( "cases", metavar="path_to__case", @@ -563,6 +580,7 @@ def main(): options.clean_up_flag, options.verbose_flag, options.gc_flag, + options.memory64_flag, options.parl_flag, options.qemu_flag, options.qemu_firmware, @@ -589,6 +607,7 @@ def main(): options.clean_up_flag, options.verbose_flag, options.gc_flag, + options.memory64_flag, options.qemu_flag, options.qemu_firmware, options.log, diff --git a/tests/wamr-test-suites/spec-test-script/gc_ignore_cases.patch b/tests/wamr-test-suites/spec-test-script/gc_ignore_cases.patch index a627a38f6..bc91d6b06 100644 --- a/tests/wamr-test-suites/spec-test-script/gc_ignore_cases.patch +++ b/tests/wamr-test-suites/spec-test-script/gc_ignore_cases.patch @@ -9,78 +9,6 @@ index 335496f0..5b975028 100644 - "integer representation too long" + "invalid type flag" ;; In GC extension, the first byte in rectype define is just one byte, not LEB128 encoded. ) -diff --git a/test/core/binary.wast b/test/core/binary.wast -index 1661a1c6..84c716b9 100644 ---- a/test/core/binary.wast -+++ b/test/core/binary.wast -@@ -1082,7 +1082,7 @@ - ) - - ;; 1 br_table target declared, 2 given --(assert_malformed -+(;assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01" ;; type section -@@ -1132,3 +1132,4 @@ - ) - "unexpected content after last section" - ) -+;) -diff --git a/test/core/data.wast b/test/core/data.wast -index a5c87fbb..6f948bae 100644 ---- a/test/core/data.wast -+++ b/test/core/data.wast -@@ -306,9 +306,10 @@ - "\02\01\41\00\0b" ;; active data segment 0 for memory 1 - "\00" ;; empty vec(byte) - ) -- "unknown memory 1" -+ "unknown memory" - ) - -+(; not supported by wat2wasm - ;; Data segment with memory index 0 (no memory section) - (assert_invalid - (module binary -@@ -317,7 +318,7 @@ - "\00\41\00\0b" ;; active data segment 0 for memory 0 - "\00" ;; empty vec(byte) - ) -- "unknown memory 0" -+ "unknown memory" - ) - - ;; Data segment with memory index 1 (no memory section) -@@ -328,7 +329,7 @@ - "\02\01\41\00\0b" ;; active data segment 0 for memory 1 - "\00" ;; empty vec(byte) - ) -- "unknown memory 1" -+ "unknown memory" - ) - - ;; Data segment with memory index 1 and vec(byte) as above, -@@ -348,7 +349,7 @@ - "\20\21\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f" - "\30\31\32\33\34\35\36\37\38\39\3a\3b\3c\3d" - ) -- "unknown memory 1" -+ "unknown memory" - ) - - ;; Data segment with memory index 1 and specially crafted vec(byte) after. -@@ -368,8 +369,9 @@ - "\20\21\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f" - "\30\31\32\33\34\35\36\37\38\39\3a\3b\3c\3d" - ) -- "unknown memory 1" -+ "unknown memory" - ) -+;) - - - ;; Invalid offsets diff --git a/test/core/elem.wast b/test/core/elem.wast index df1610f6..32c1d8b3 100644 --- a/test/core/elem.wast @@ -268,196 +196,11 @@ index 00000000..32650644 + ) + "unsupported initializer expression for table" +) -diff --git a/test/core/gc/ref_test.wast b/test/core/gc/ref_test.wast -index 590b81b8..e0aa49ed 100644 ---- a/test/core/gc/ref_test.wast -+++ b/test/core/gc/ref_test.wast -@@ -310,15 +310,16 @@ - (br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 11))))) - (br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 12))))) - -- (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 1))))) -- (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 2))))) -+ ;; Must have explicit sub relationship -+ ;; (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 1))))) -+ ;; (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 2))))) - -- (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 11))))) -- (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 12))))) -+ ;; (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 11))))) -+ ;; (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 12))))) - -- (br_if $l (i32.eqz (ref.test (ref $t2') (table.get (i32.const 2))))) -+ ;; (br_if $l (i32.eqz (ref.test (ref $t2') (table.get (i32.const 2))))) - -- (br_if $l (i32.eqz (ref.test (ref $t2) (table.get (i32.const 12))))) -+ ;; (br_if $l (i32.eqz (ref.test (ref $t2) (table.get (i32.const 12))))) - - (return) - ) diff --git a/test/core/gc/type-subtyping.wast b/test/core/gc/type-subtyping.wast -index a9022fc3..4e22e91b 100644 +index a9022fc3..4aa36e2a 100644 --- a/test/core/gc/type-subtyping.wast +++ b/test/core/gc/type-subtyping.wast -@@ -112,6 +112,8 @@ - ) - ) - -+;; don't support recursive type equality and subtype check -+(; - (module - (rec (type $f1 (sub (func))) (type (struct (field (ref $f1))))) - (rec (type $f2 (sub (func))) (type (struct (field (ref $f2))))) -@@ -135,6 +137,7 @@ - (func $g (type $g2)) - (global (ref $g1) (ref.func $g)) - ) -+;) - - (assert_invalid - (module -@@ -156,6 +159,8 @@ - (global (ref $f1) (ref.func $g)) - ) - -+;; don't support recursive type equality and subtype check -+(; - (module - (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1)))))) - (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2)))))) -@@ -201,6 +206,7 @@ - (global (ref $g12) (ref.func $g12)) - (global (ref $g22) (ref.func $g12)) - ) -+;) - - (assert_invalid - (module -@@ -226,6 +232,8 @@ - - ;; Runtime types - -+;; don't support recursive type equality and subtype check -+(; - (module - (type $t0 (sub (func (result (ref null func))))) - (rec (type $t1 (sub $t0 (func (result (ref null $t1)))))) -@@ -286,6 +294,7 @@ - (assert_trap (invoke "fail4") "cast") - (assert_trap (invoke "fail5") "cast") - (assert_trap (invoke "fail6") "cast") -+;) - - (module - (type $t1 (sub (func))) -@@ -316,7 +325,8 @@ - (assert_trap (invoke "fail3") "cast") - (assert_trap (invoke "fail4") "cast") - -- -+;; don't support recursive type equality and subtype check -+(; - (module - (rec (type $f1 (sub (func))) (type (struct (field (ref $f1))))) - (rec (type $f2 (sub (func))) (type (struct (field (ref $f2))))) -@@ -346,6 +356,7 @@ - ) - ) - (assert_return (invoke "run") (i32.const 1)) -+;) - - (module - (rec (type $f1 (sub (func))) (type (struct (field (ref $f1))))) -@@ -370,6 +381,8 @@ - ) - (assert_return (invoke "run") (i32.const 1)) - -+;; don't support recursive type equality and subtype check -+(; - (module - (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1)))))) - (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2)))))) -@@ -390,7 +403,6 @@ - ) - (assert_return (invoke "run") (i32.const 1) (i32.const 1)) - -- - (module - (rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11)))))) - (rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21)))))) -@@ -429,7 +441,9 @@ - (i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1) - (i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1) - ) -+;) - -+(; we use normalized function type index - (module - (rec (type $f11 (sub (func))) (type $f12 (sub $f11 (func)))) - (rec (type $f21 (sub (func))) (type $f22 (sub $f11 (func)))) -@@ -439,6 +453,7 @@ - ) - ) - (assert_return (invoke "run") (i32.const 0)) -+;) - - (module - (rec (type $f01 (sub (func))) (type $f02 (sub $f01 (func)))) -@@ -547,15 +562,15 @@ - (func (import "M3" "g") (type $g1)) - ) - --(module -- (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1)))))) -- (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2)))))) -- (rec -- (type $g2 (sub $f2 (func))) -- (type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2))))) -- ) -- (func (export "g") (type $g2)) --) -+;; (module -+;; (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1)))))) -+;; (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2)))))) -+;; (rec -+;; (type $g2 (sub $f2 (func))) -+;; (type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2))))) -+;; ) -+;; (func (export "g") (type $g2)) -+;; ) - (register "M4") - (module - (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1)))))) -@@ -597,17 +612,17 @@ - (func (import "M6" "g") (type $f1)) - ) - --(module -- (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1)))))) -- (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2)))))) -- (rec -- (type $g2 (sub $f2 (func))) -- (type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2))))) -- ) -- (rec (type $h (sub $g2 (func))) (type (struct))) -- (func (export "h") (type $h)) --) --(register "M7") -+;; (module -+;; (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1)))))) -+;; (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2)))))) -+;; (rec -+;; (type $g2 (sub $f2 (func))) -+;; (type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2))))) -+;; ) -+;; (rec (type $h (sub $g2 (func))) (type (struct))) -+;; (func (export "h") (type $h)) -+;; ) -+;; (register "M7") - (module - (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1)))))) - (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2)))))) -@@ -740,7 +755,7 @@ +@@ -740,7 +740,7 @@ "sub type" ) @@ -466,7 +209,7 @@ index a9022fc3..4e22e91b 100644 (module (type $f0 (sub (func (param i32) (result i32)))) (type $s0 (sub $f0 (struct))) -@@ -764,7 +779,7 @@ +@@ -764,7 +764,7 @@ "sub type" ) @@ -475,7 +218,7 @@ index a9022fc3..4e22e91b 100644 (module (type $s0 (sub (struct))) (type $f0 (sub $s0 (func (param i32) (result i32)))) -@@ -772,7 +787,7 @@ +@@ -772,7 +772,7 @@ "sub type" ) @@ -1262,29 +1005,3 @@ index 0b2d26f7..bdab6a01 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/unreached-valid.wast b/test/core/unreached-valid.wast -index f3feb0f3..d8ef8743 100644 ---- a/test/core/unreached-valid.wast -+++ b/test/core/unreached-valid.wast -@@ -60,7 +60,7 @@ - - ;; Validation after unreachable - --(module -+(;module - (func (export "meet-bottom") - (block (result f64) - (block (result f32) -@@ -76,7 +76,6 @@ - - (assert_trap (invoke "meet-bottom") "unreachable") - -- - ;; Bottom heap type - - (module -@@ -106,3 +105,4 @@ - (unreachable) - ) - ) -+;) diff --git a/tests/wamr-test-suites/spec-test-script/memory64.patch b/tests/wamr-test-suites/spec-test-script/memory64.patch new file mode 100644 index 000000000..739a1df60 --- /dev/null +++ b/tests/wamr-test-suites/spec-test-script/memory64.patch @@ -0,0 +1,28 @@ +diff --git a/test/core/memory.wast b/test/core/memory.wast +index 1dd5b84..497b69f 100644 +--- a/test/core/memory.wast ++++ b/test/core/memory.wast +@@ -76,17 +76,17 @@ + "memory size must be at most 65536 pages (4GiB)" + ) + +-(assert_invalid ++(assert_malformed + (module quote "(memory 0x1_0000_0000)") +- "memory size must be at most 65536 pages (4GiB)" ++ "i32 constant out of range" + ) +-(assert_invalid ++(assert_malformed + (module quote "(memory 0x1_0000_0000 0x1_0000_0000)") +- "memory size must be at most 65536 pages (4GiB)" ++ "i32 constant out of range" + ) +-(assert_invalid ++(assert_malformed + (module quote "(memory 0 0x1_0000_0000)") +- "memory size must be at most 65536 pages (4GiB)" ++ "i32 constant out of range" + ) + + (module diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index 344e4fd44..13229d977 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -313,6 +313,9 @@ parser.add_argument('--multi-thread', default=False, action='store_true', parser.add_argument('--gc', default=False, action='store_true', help='Test with GC') +parser.add_argument('--memory64', default=False, action='store_true', + help='Test with Memory64') + parser.add_argument('--qemu', default=False, action='store_true', help="Enable QEMU") @@ -1071,7 +1074,7 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): log("Compiling WASM to '%s'" % wasm_tempfile) # default arguments - if opts.gc: + if opts.gc or opts.memory64: cmd = [opts.wast2wasm, "-u", "-d", wast_tempfile, "-o", wasm_tempfile] elif opts.eh: cmd = [opts.wast2wasm, "--enable-thread", "--no-check", "--enable-exceptions", "--enable-tail-call", wast_tempfile, "-o", wasm_tempfile ] @@ -1116,6 +1119,9 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = ' cmd.append("--enable-gc") cmd.append("--enable-tail-call") + if opts.memory64: + cmd.append("--enable-memory64") + if output == 'object': cmd.append("--format=object") elif output == 'ir': diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 933583816..0c56acac4 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -23,6 +23,7 @@ function help() echo "-p enable multi thread feature" echo "-S enable SIMD feature" echo "-G enable GC feature" + echo "-W enable memory64 feature" echo "-X enable XIP feature" echo "-e enable exception handling" echo "-x test SGX" @@ -50,6 +51,7 @@ ENABLE_MULTI_THREAD=0 COLLECT_CODE_COVERAGE=0 ENABLE_SIMD=0 ENABLE_GC=0 +ENABLE_MEMORY64=0 ENABLE_XIP=0 ENABLE_EH=0 ENABLE_DEBUG_VERSION=0 @@ -72,7 +74,7 @@ WASI_TESTSUITE_COMMIT="ee807fc551978490bf1c277059aabfa1e589a6c2" TARGET_LIST=("AARCH64" "AARCH64_VFP" "ARMV7" "ARMV7_VFP" "THUMBV7" "THUMBV7_VFP" \ "RISCV32" "RISCV32_ILP32F" "RISCV32_ILP32D" "RISCV64" "RISCV64_LP64F" "RISCV64_LP64D") -while getopts ":s:cabgvt:m:MCpSXexwPGQF:j:T:" opt +while getopts ":s:cabgvt:m:MCpSXexwWPGQF:j:T:" opt do OPT_PARSED="TRUE" case $opt in @@ -131,6 +133,10 @@ do echo "enable multi module feature" ENABLE_MULTI_MODULE=1 ;; + W) + echo "enable wasm64(memory64) feature" + ENABLE_MEMORY64=1 + ;; C) echo "enable code coverage" COLLECT_CODE_COVERAGE=1 @@ -478,6 +484,29 @@ function spec_test() popd fi + # update memory64 cases + if [[ ${ENABLE_MEMORY64} == 1 ]]; then + echo "checkout spec for memory64 proposal" + + popd + rm -fr spec + # check spec test cases for memory64 + git clone -b main --single-branch https://github.com/WebAssembly/memory64.git spec + pushd spec + + git restore . && git clean -ffd . + # Reset to commit: "Merge remote-tracking branch 'upstream/main' into merge2" + git reset --hard 48e69f394869c55b7bbe14ac963c09f4605490b6 + git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast + git apply ../../spec-test-script/ignore_cases.patch + git apply ../../spec-test-script/memory64.patch + + echo "compile the reference intepreter" + pushd interpreter + make + popd + fi + popd echo $(pwd) @@ -488,7 +517,7 @@ function spec_test() local ARGS_FOR_SPEC_TEST="" - # multi-module only enable in interp mode + # multi-module only enable in interp mode and aot mode if [[ 1 == ${ENABLE_MULTI_MODULE} ]]; then if [[ $1 == 'classic-interp' || $1 == 'fast-interp' || $1 == 'aot' ]]; then ARGS_FOR_SPEC_TEST+="-M " @@ -537,6 +566,13 @@ function spec_test() ARGS_FOR_SPEC_TEST+="--gc " fi + # wasm64(memory64) is only enabled in interp and aot mode + if [[ 1 == ${ENABLE_MEMORY64} ]]; then + if [[ $1 == 'classic-interp' || $1 == 'aot' ]]; then + ARGS_FOR_SPEC_TEST+="--memory64 " + fi + fi + if [[ ${ENABLE_QEMU} == 1 ]]; then ARGS_FOR_SPEC_TEST+="--qemu " ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} " @@ -833,6 +869,12 @@ function trigger() EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MULTI_MODULE=0" fi + if [[ ${ENABLE_MEMORY64} == 1 ]];then + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MEMORY64=1" + else + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MEMORY64=0" + fi + if [[ ${ENABLE_MULTI_THREAD} == 1 ]];then EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIB_PTHREAD=1" fi