mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-07-11 06:53:16 +00:00
Compare commits
69 Commits
fa773b4e8d
...
9a3340bed2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9a3340bed2 | ||
![]() |
1e41519977 | ||
![]() |
e414a327a0 | ||
![]() |
8289452abb | ||
![]() |
70c39bae77 | ||
![]() |
92e5f5f123 | ||
![]() |
7471d5a5d0 | ||
![]() |
f449b79a31 | ||
![]() |
64cafaff1e | ||
![]() |
ea408ab6c0 | ||
![]() |
71c07f3e4e | ||
![]() |
e5091e47ea | ||
![]() |
aa53d648fa | ||
![]() |
a29f3943ef | ||
![]() |
8414a20dfe | ||
![]() |
db7714f0f5 | ||
![]() |
4bf799c3af | ||
![]() |
cba9001749 | ||
![]() |
4ebd1bb597 | ||
![]() |
b3ce192e1a | ||
![]() |
c9b8c16088 | ||
![]() |
6dfb410869 | ||
![]() |
2f0750a6fe | ||
![]() |
20be1d33fe | ||
![]() |
965f2452c8 | ||
![]() |
05e3a09150 | ||
![]() |
745da82cd6 | ||
![]() |
7bbdbf5212 | ||
![]() |
d7e3e376a9 | ||
![]() |
0d001c4c38 | ||
![]() |
8e60feb181 | ||
![]() |
0343aaf8c3 | ||
![]() |
2fe7105e8d | ||
![]() |
9becf65d1e | ||
![]() |
78e68cec83 | ||
![]() |
75bf9797a2 | ||
![]() |
5478d267f4 | ||
![]() |
3a087c4244 | ||
![]() |
928598f1ce | ||
![]() |
c932597057 | ||
![]() |
d52f083ac0 | ||
![]() |
c4623e2cb5 | ||
![]() |
7f968f5926 | ||
![]() |
07c23cb98e | ||
![]() |
ea5757f1d7 | ||
![]() |
4d6b8dcd5d | ||
![]() |
99c75b53db | ||
![]() |
933f8124b0 | ||
![]() |
769d16eaab | ||
![]() |
350af77b03 | ||
![]() |
97e9502bb3 | ||
![]() |
48a97736b3 | ||
![]() |
602e86adc3 | ||
![]() |
79cb4366ae | ||
![]() |
b20ebc2724 | ||
![]() |
85efe08431 | ||
![]() |
93ef19b0ca | ||
![]() |
6a00874f2f | ||
![]() |
61cb97221e | ||
![]() |
ae6e490ad5 | ||
![]() |
16c46751ac | ||
![]() |
1c12a32066 | ||
![]() |
938503af38 | ||
![]() |
62bb6e8158 | ||
![]() |
aa1ff778b9 | ||
![]() |
2a303861cc | ||
![]() |
670aa83985 | ||
![]() |
d9325b2549 | ||
![]() |
e3dcf4f8ac |
53
.github/actions/install-wasi-sdk-wabt/action.yml
vendored
53
.github/actions/install-wasi-sdk-wabt/action.yml
vendored
|
@ -30,14 +30,23 @@ runs:
|
||||||
if: ${{ startsWith(inputs.os, 'ubuntu') }}
|
if: ${{ startsWith(inputs.os, 'ubuntu') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
echo "Downloading wasi-sdk for Ubuntu..."
|
||||||
sudo wget -O wasi-sdk.tar.gz --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz
|
sudo wget -O wasi-sdk.tar.gz --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz
|
||||||
|
|
||||||
|
echo "Extracting wasi-sdk..."
|
||||||
sudo tar -xf wasi-sdk.tar.gz
|
sudo tar -xf wasi-sdk.tar.gz
|
||||||
sudo ln -sf wasi-sdk-25.0-x86_64-linux/ wasi-sdk
|
sudo ln -sf wasi-sdk-25.0-x86_64-linux/ wasi-sdk
|
||||||
|
|
||||||
|
echo "Downloading wabt for Ubuntu..."
|
||||||
sudo wget -O wabt.tar.gz --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/1.0.37/wabt-1.0.37-ubuntu-20.04.tar.gz
|
sudo wget -O wabt.tar.gz --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/1.0.37/wabt-1.0.37-ubuntu-20.04.tar.gz
|
||||||
|
|
||||||
|
echo "Extracting wabt..."
|
||||||
sudo tar -xf wabt.tar.gz
|
sudo tar -xf wabt.tar.gz
|
||||||
sudo ln -sf wabt-1.0.37 wabt
|
sudo ln -sf wabt-1.0.37 wabt
|
||||||
|
|
||||||
/opt/wasi-sdk/bin/clang --version
|
/opt/wasi-sdk/bin/clang --version
|
||||||
/opt/wabt/bin/wasm-interp --version
|
/opt/wabt/bin/wasm-interp --version
|
||||||
|
|
||||||
echo "::notice::wasi-sdk-25 and wabt-1.0.37 installed on ubuntu"
|
echo "::notice::wasi-sdk-25 and wabt-1.0.37 installed on ubuntu"
|
||||||
working-directory: /opt
|
working-directory: /opt
|
||||||
|
|
||||||
|
@ -45,14 +54,23 @@ runs:
|
||||||
if: ${{ inputs.os == 'macos-13' }}
|
if: ${{ inputs.os == 'macos-13' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
echo "Downloading wasi-sdk for macOS-13..."
|
||||||
sudo wget -O wasi-sdk.tar.gz --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-macos.tar.gz
|
sudo wget -O wasi-sdk.tar.gz --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-macos.tar.gz
|
||||||
|
|
||||||
|
echo "Extracting wasi-sdk..."
|
||||||
sudo tar -xf wasi-sdk.tar.gz
|
sudo tar -xf wasi-sdk.tar.gz
|
||||||
sudo ln -sf wasi-sdk-25.0-x86_64-macos wasi-sdk
|
sudo ln -sf wasi-sdk-25.0-x86_64-macos wasi-sdk
|
||||||
|
|
||||||
|
echo "Downloading wabt for macOS-13..."
|
||||||
sudo wget -O wabt.tar.gz --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/1.0.36/wabt-1.0.36-macos-12.tar.gz
|
sudo wget -O wabt.tar.gz --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/1.0.36/wabt-1.0.36-macos-12.tar.gz
|
||||||
|
|
||||||
|
echo "Extracting wabt..."
|
||||||
sudo tar -xf wabt.tar.gz
|
sudo tar -xf wabt.tar.gz
|
||||||
sudo ln -sf wabt-1.0.36 wabt
|
sudo ln -sf wabt-1.0.36 wabt
|
||||||
|
|
||||||
/opt/wasi-sdk/bin/clang --version
|
/opt/wasi-sdk/bin/clang --version
|
||||||
/opt/wabt/bin/wasm-interp --version
|
/opt/wabt/bin/wasm-interp --version
|
||||||
|
|
||||||
echo "::notice::wasi-sdk-25 and wabt-1.0.36 installed on macos-13"
|
echo "::notice::wasi-sdk-25 and wabt-1.0.36 installed on macos-13"
|
||||||
working-directory: /opt
|
working-directory: /opt
|
||||||
|
|
||||||
|
@ -60,21 +78,48 @@ runs:
|
||||||
if: ${{ inputs.os == 'macos-14' }}
|
if: ${{ inputs.os == 'macos-14' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
echo "Downloading wasi-sdk for macOS-14..."
|
||||||
sudo wget -O wasi-sdk.tar.gz --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-arm64-macos.tar.gz
|
sudo wget -O wasi-sdk.tar.gz --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-arm64-macos.tar.gz
|
||||||
|
|
||||||
|
echo "Extracting wasi-sdk..."
|
||||||
sudo tar -xf wasi-sdk.tar.gz
|
sudo tar -xf wasi-sdk.tar.gz
|
||||||
sudo ln -sf wasi-sdk-25.0-arm64-macos wasi-sdk
|
sudo ln -sf wasi-sdk-25.0-arm64-macos wasi-sdk
|
||||||
|
|
||||||
|
echo "Downloading wabt for macOS-14..."
|
||||||
sudo wget -O wabt.tar.gz --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/1.0.37/wabt-1.0.37-macos-14.tar.gz
|
sudo wget -O wabt.tar.gz --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/1.0.37/wabt-1.0.37-macos-14.tar.gz
|
||||||
|
|
||||||
|
echo "Extracting wabt..."
|
||||||
sudo tar -xf wabt.tar.gz
|
sudo tar -xf wabt.tar.gz
|
||||||
sudo ln -sf wabt-1.0.37 wabt
|
sudo ln -sf wabt-1.0.37 wabt
|
||||||
|
|
||||||
/opt/wasi-sdk/bin/clang --version
|
/opt/wasi-sdk/bin/clang --version
|
||||||
/opt/wabt/bin/wasm-interp --version
|
/opt/wabt/bin/wasm-interp --version
|
||||||
|
|
||||||
echo "::notice::wasi-sdk-25 and wabt-1.0.37 installed on macos-14"
|
echo "::notice::wasi-sdk-25 and wabt-1.0.37 installed on macos-14"
|
||||||
working-directory: /opt
|
working-directory: /opt
|
||||||
|
|
||||||
#TODO: Add support for Windows
|
|
||||||
- name: Set up wasi-sdk and wabt on Windows
|
- name: Set up wasi-sdk and wabt on Windows
|
||||||
if: ${{ startsWith(inputs.os, 'windows') }}
|
if: ${{ startsWith(inputs.os, 'windows') }}
|
||||||
shell: powershell
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "::notice::Support for Windows is not implemented yet"
|
choco install -y wget
|
||||||
exit 1
|
|
||||||
|
mkdir -p /opt/wasi-sdk
|
||||||
|
mkdir -p /opt/wabt
|
||||||
|
|
||||||
|
echo "Downloading wasi-sdk for Windows..."
|
||||||
|
wget -O wasi-sdk.tar.gz --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-windows.tar.gz
|
||||||
|
|
||||||
|
echo "Extracting wasi-sdk..."
|
||||||
|
tar --strip-components=1 -xf wasi-sdk.tar.gz -C /opt/wasi-sdk
|
||||||
|
|
||||||
|
echo "Downloading wabt for Windows..."
|
||||||
|
wget -O wabt.tar.gz --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/1.0.37/wabt-1.0.37-windows.tar.gz
|
||||||
|
|
||||||
|
echo "Extracting wabt..."
|
||||||
|
tar --strip-components=1 -xf wabt.tar.gz -C /opt/wabt
|
||||||
|
|
||||||
|
/opt/wasi-sdk/bin/clang --version
|
||||||
|
/opt/wabt/bin/wasm-interp --version
|
||||||
|
|
||||||
|
echo "::notice::wasi-sdk-25 and wabt-1.0.37 installed on Windows"
|
||||||
|
|
5
.github/workflows/build_iwasm_release.yml
vendored
5
.github/workflows/build_iwasm_release.yml
vendored
|
@ -23,7 +23,7 @@ on:
|
||||||
type: string
|
type: string
|
||||||
required: true
|
required: true
|
||||||
upload_url:
|
upload_url:
|
||||||
description: a semantic version number. it is required when `release` is true.
|
description: upload binary assets to the URL of release
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
ver_num:
|
ver_num:
|
||||||
|
@ -137,7 +137,8 @@ jobs:
|
||||||
- name: compress the binary on non-Windows
|
- name: compress the binary on non-Windows
|
||||||
if: inputs.runner != 'windows-latest'
|
if: inputs.runner != 'windows-latest'
|
||||||
run: |
|
run: |
|
||||||
tar czf iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm
|
# Follow the symlink to the actual binary file
|
||||||
|
tar --dereference -czf iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm
|
||||||
zip iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.zip iwasm
|
zip iwasm${{ matrix.suffix }}-${{ inputs.ver_num }}-${{ inputs.runner }}.zip iwasm
|
||||||
working-directory: ${{ inputs.cwd }}/build
|
working-directory: ${{ inputs.cwd }}/build
|
||||||
|
|
||||||
|
|
5
.github/workflows/build_wamrc.yml
vendored
5
.github/workflows/build_wamrc.yml
vendored
|
@ -23,7 +23,7 @@ on:
|
||||||
type: string
|
type: string
|
||||||
required: true
|
required: true
|
||||||
upload_url:
|
upload_url:
|
||||||
description: a semantic version number. it is required when `release` is true.
|
description: upload binary assets to the URL of release
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
ver_num:
|
ver_num:
|
||||||
|
@ -73,7 +73,8 @@ jobs:
|
||||||
- name: compress the binary on non-Windows
|
- name: compress the binary on non-Windows
|
||||||
if: inputs.runner != 'windows-latest' && inputs.release
|
if: inputs.runner != 'windows-latest' && inputs.release
|
||||||
run: |
|
run: |
|
||||||
tar czf wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamrc
|
# Follow the symlink to the actual binary file
|
||||||
|
tar --dereference -czf wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamrc
|
||||||
zip wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.zip wamrc
|
zip wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.zip wamrc
|
||||||
working-directory: wamr-compiler/build
|
working-directory: wamr-compiler/build
|
||||||
|
|
||||||
|
|
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
|
@ -53,7 +53,7 @@ jobs:
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3.28.18
|
uses: github/codeql-action/init@v3.29.0
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ jobs:
|
||||||
- run: |
|
- run: |
|
||||||
./.github/scripts/codeql_buildscript.sh
|
./.github/scripts/codeql_buildscript.sh
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3.28.18
|
uses: github/codeql-action/analyze@v3.29.0
|
||||||
with:
|
with:
|
||||||
category: "/language:${{matrix.language}}"
|
category: "/language:${{matrix.language}}"
|
||||||
upload: false
|
upload: false
|
||||||
|
@ -99,7 +99,7 @@ jobs:
|
||||||
output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif
|
output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif
|
||||||
|
|
||||||
- name: Upload CodeQL results to code scanning
|
- name: Upload CodeQL results to code scanning
|
||||||
uses: github/codeql-action/upload-sarif@v3.28.18
|
uses: github/codeql-action/upload-sarif@v3.29.0
|
||||||
with:
|
with:
|
||||||
sarif_file: ${{ steps.step1.outputs.sarif-output }}
|
sarif_file: ${{ steps.step1.outputs.sarif-output }}
|
||||||
category: "/language:${{matrix.language}}"
|
category: "/language:${{matrix.language}}"
|
||||||
|
|
174
.github/workflows/compilation_on_android_ubuntu.yml
vendored
174
.github/workflows/compilation_on_android_ubuntu.yml
vendored
|
@ -618,49 +618,6 @@ jobs:
|
||||||
llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }}
|
llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }}
|
||||||
running_mode: aot
|
running_mode: aot
|
||||||
test_option: $WAMR_COMPILER_TEST_OPTIONS
|
test_option: $WAMR_COMPILER_TEST_OPTIONS
|
||||||
exclude:
|
|
||||||
# incompatible modes and features
|
|
||||||
# classic-interp doesn't support simd
|
|
||||||
- running_mode: "classic-interp"
|
|
||||||
test_option: $SIMD_TEST_OPTIONS
|
|
||||||
# llvm jit doesn't support multi module
|
|
||||||
- running_mode: "jit"
|
|
||||||
test_option: $MULTI_MODULES_TEST_OPTIONS
|
|
||||||
# fast-jit doesn't support multi module, simd
|
|
||||||
- running_mode: "fast-jit"
|
|
||||||
test_option: $MULTI_MODULES_TEST_OPTIONS
|
|
||||||
- running_mode: "fast-jit"
|
|
||||||
test_option: $SIMD_TEST_OPTIONS
|
|
||||||
# multi-tier-jit doesn't support multi module, simd
|
|
||||||
- running_mode: "multi-tier-jit"
|
|
||||||
test_option: $MULTI_MODULES_TEST_OPTIONS
|
|
||||||
- running_mode: "multi-tier-jit"
|
|
||||||
test_option: $SIMD_TEST_OPTIONS
|
|
||||||
# fast-jit and multi-tier-jit don't support GC
|
|
||||||
- running_mode: "fast-jit"
|
|
||||||
test_option: $GC_TEST_OPTIONS
|
|
||||||
- running_mode: "multi-tier-jit"
|
|
||||||
test_option: $GC_TEST_OPTIONS
|
|
||||||
# fast-interp, fast-jit, llvm-jit, multi-tier-jit don't support Memory64
|
|
||||||
- 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
|
|
||||||
# aot, fast-interp, fast-jit, llvm-jit, multi-tier-jit don't support Multi Memory
|
|
||||||
- running_mode: "aot"
|
|
||||||
test_option: $MULTI_MEMORY_TEST_OPTIONS
|
|
||||||
- running_mode: "fast-interp"
|
|
||||||
test_option: $MULTI_MEMORY_TEST_OPTIONS
|
|
||||||
- running_mode: "fast-jit"
|
|
||||||
test_option: $MULTI_MEMORY_TEST_OPTIONS
|
|
||||||
- running_mode: "jit"
|
|
||||||
test_option: $MULTI_MEMORY_TEST_OPTIONS
|
|
||||||
- running_mode: "multi-tier-jit"
|
|
||||||
test_option: $MULTI_MEMORY_TEST_OPTIONS
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
|
@ -682,15 +639,6 @@ jobs:
|
||||||
with:
|
with:
|
||||||
os: ${{ matrix.os }}
|
os: ${{ matrix.os }}
|
||||||
|
|
||||||
# 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: |
|
|
||||||
git clone https://github.com/WebAssembly/wasi-libc
|
|
||||||
cd wasi-libc
|
|
||||||
make -j AR=/opt/wasi-sdk/bin/llvm-ar NM=/opt/wasi-sdk/bin/llvm-nm CC=/opt/wasi-sdk/bin/clang THREAD_MODEL=posix
|
|
||||||
echo "SYSROOT_PATH=$PWD/sysroot" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: set env variable(if llvm are used)
|
- name: set env variable(if llvm are used)
|
||||||
if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit' || matrix.running_mode == 'multi-tier-jit'
|
if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit' || matrix.running_mode == 'multi-tier-jit'
|
||||||
run: echo "USE_LLVM=true" >> $GITHUB_ENV
|
run: echo "USE_LLVM=true" >> $GITHUB_ENV
|
||||||
|
@ -727,7 +675,7 @@ jobs:
|
||||||
|
|
||||||
- name: Build WASI thread tests
|
- name: Build WASI thread tests
|
||||||
if: matrix.test_option == '$WASI_TEST_OPTIONS'
|
if: matrix.test_option == '$WASI_TEST_OPTIONS'
|
||||||
run: bash build.sh --sysroot "$SYSROOT_PATH"
|
run: bash build.sh
|
||||||
working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/
|
working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/
|
||||||
|
|
||||||
- name: build socket api tests
|
- name: build socket api tests
|
||||||
|
@ -773,123 +721,3 @@ jobs:
|
||||||
eval $(opam env)
|
eval $(opam env)
|
||||||
./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
|
./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
|
||||||
working-directory: ./tests/wamr-test-suites
|
working-directory: ./tests/wamr-test-suites
|
||||||
|
|
||||||
test-wamr-ide:
|
|
||||||
needs:
|
|
||||||
[
|
|
||||||
build_iwasm
|
|
||||||
]
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
env:
|
|
||||||
PYTHON_VERSION: '3.10'
|
|
||||||
PYTHON_UBUNTU_STANDALONE_BUILD: https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-unknown-linux-gnu-install_only.tar.gz
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: install dependencies
|
|
||||||
run: |
|
|
||||||
rustup target add wasm32-wasip1
|
|
||||||
sudo apt update && sudo apt-get install -y lld ninja-build
|
|
||||||
npm install
|
|
||||||
working-directory: test-tools/wamr-ide/VSCode-Extension
|
|
||||||
|
|
||||||
- name: code style check
|
|
||||||
run: |
|
|
||||||
npm install --save-dev prettier
|
|
||||||
npm run prettier-format-check
|
|
||||||
working-directory: test-tools/wamr-ide/VSCode-Extension
|
|
||||||
|
|
||||||
- name: build iwasm with source debugging feature
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DWAMR_BUILD_DEBUG_INTERP=1 -DWAMR_BUILD_REF_TYPES=1
|
|
||||||
make
|
|
||||||
working-directory: product-mini/platforms/linux
|
|
||||||
|
|
||||||
- name: Cache LLDB
|
|
||||||
id: cache-lldb
|
|
||||||
uses: actions/cache@v4
|
|
||||||
env:
|
|
||||||
cache-name: cache-lldb-vscode
|
|
||||||
with:
|
|
||||||
path: test-tools/wamr-ide/VSCode-Extension/resource/debug/linux
|
|
||||||
key: ${{ env.cache-name }}-${{ hashFiles('build-scripts/lldb_wasm.patch') }}-${{ env.PYTHON_UBUNTU_STANDALONE_BUILD }}
|
|
||||||
|
|
||||||
- if: ${{ steps.cache-lldb.outputs.cache-hit != 'true' }}
|
|
||||||
name: get stand-alone python ubuntu
|
|
||||||
run: |
|
|
||||||
wget ${{ env.PYTHON_UBUNTU_STANDALONE_BUILD }} -O python.tar.gz
|
|
||||||
tar -xvf python.tar.gz
|
|
||||||
working-directory: core/deps
|
|
||||||
|
|
||||||
- if: ${{ steps.cache-lldb.outputs.cache-hit != 'true' }}
|
|
||||||
name: download llvm
|
|
||||||
run: |
|
|
||||||
wget https://github.com/llvm/llvm-project/archive/1f27fe6128769f00197925c3b8f6abb9d0e5cd2e.zip
|
|
||||||
unzip -q 1f27fe6128769f00197925c3b8f6abb9d0e5cd2e.zip
|
|
||||||
mv llvm-project-1f27fe6128769f00197925c3b8f6abb9d0e5cd2e llvm-project
|
|
||||||
working-directory: core/deps
|
|
||||||
|
|
||||||
- if: ${{ steps.cache-lldb.outputs.cache-hit != 'true' }}
|
|
||||||
name: apply wamr patch
|
|
||||||
run: |
|
|
||||||
git init
|
|
||||||
git config user.email "action@github.com"
|
|
||||||
git config user.name "github action"
|
|
||||||
git apply ../../../build-scripts/lldb_wasm.patch
|
|
||||||
working-directory: core/deps/llvm-project
|
|
||||||
|
|
||||||
- if: ${{ steps.cache-lldb.outputs.cache-hit != 'true' }}
|
|
||||||
name: build lldb ubuntu
|
|
||||||
run: |
|
|
||||||
echo "start to build lldb..."
|
|
||||||
mkdir -p wamr-lldb
|
|
||||||
cmake -S ./llvm -B build \
|
|
||||||
-G Ninja \
|
|
||||||
-DCMAKE_INSTALL_PREFIX=../wamr-lldb \
|
|
||||||
-DCMAKE_BUILD_TYPE:STRING="Release" \
|
|
||||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
|
||||||
-DLLVM_ENABLE_PROJECTS="clang;lldb" \
|
|
||||||
-DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly" \
|
|
||||||
-DLLVM_BUILD_BENCHMARKS:BOOL=OFF \
|
|
||||||
-DLLVM_BUILD_DOCS:BOOL=OFF \
|
|
||||||
-DLLVM_BUILD_EXAMPLES:BOOL=OFF \
|
|
||||||
-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \
|
|
||||||
-DLLVM_BUILD_TESTS:BOOL=OFF \
|
|
||||||
-DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \
|
|
||||||
-DLLVM_INCLUDE_DOCS:BOOL=OFF \
|
|
||||||
-DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \
|
|
||||||
-DLLVM_INCLUDE_TESTS:BOOL=OFF \
|
|
||||||
-DLLVM_ENABLE_BINDINGS:BOOL=OFF \
|
|
||||||
-DLLVM_ENABLE_LIBXML2:BOOL=ON \
|
|
||||||
-DLLVM_ENABLE_LLD:BOOL=ON \
|
|
||||||
-DLLDB_ENABLE_PYTHON:BOOL=ON \
|
|
||||||
-DLLDB_EMBED_PYTHON_HOME=ON \
|
|
||||||
-DLLDB_PYTHON_HOME=.. \
|
|
||||||
-DLLDB_PYTHON_RELATIVE_PATH=lib/lldb-python \
|
|
||||||
-DPython3_EXECUTABLE="$(pwd)/../python/bin/python${{ env.PYTHON_VERSION }}"
|
|
||||||
cmake --build build --target lldb install --parallel $(nproc)
|
|
||||||
working-directory: core/deps/llvm-project
|
|
||||||
|
|
||||||
- if: ${{ steps.cache-lldb.outputs.cache-hit != 'true' }}
|
|
||||||
name: copy lldb to extension folder
|
|
||||||
run: |
|
|
||||||
mkdir -p bin
|
|
||||||
mkdir -p lib
|
|
||||||
cp ../../../../../../core/deps/llvm-project/lldb/tools/lldb-vscode/package.json ./
|
|
||||||
cp -r ../../../../../../core/deps/llvm-project/lldb/tools/lldb-vscode/syntaxes/ ./
|
|
||||||
cp ../../../../../../core/deps/llvm-project/build/bin/lldb* bin
|
|
||||||
cp ../../../../../../core/deps/llvm-project/build/lib/liblldb*.so lib
|
|
||||||
cp ../../../../../../core/deps/llvm-project/build/lib/liblldb*.so.* lib
|
|
||||||
cp -R ../../../../../../core/deps/llvm-project/build/lib/lldb-python lib
|
|
||||||
cp -R ../../../../../../core/deps/python/lib/python* lib
|
|
||||||
cp ../../../../../../core/deps/python/lib/libpython${{ env.PYTHON_VERSION }}.so.1.0 lib
|
|
||||||
working-directory: test-tools/wamr-ide/VSCode-Extension/resource/debug/linux
|
|
||||||
|
|
||||||
- name: run tests
|
|
||||||
timeout-minutes: 5
|
|
||||||
run: xvfb-run npm run test
|
|
||||||
working-directory: test-tools/wamr-ide/VSCode-Extension
|
|
||||||
|
|
44
.github/workflows/compilation_on_sgx.yml
vendored
44
.github/workflows/compilation_on_sgx.yml
vendored
|
@ -288,30 +288,24 @@ jobs:
|
||||||
sudo swapon /swapfile
|
sudo swapon /swapfile
|
||||||
sudo swapon --show
|
sudo swapon --show
|
||||||
|
|
||||||
- name: run spec tests
|
- name: run spec tests with retry
|
||||||
run: |
|
id: run_spec_tests
|
||||||
set +e
|
uses: nick-fields/retry@v3
|
||||||
source /opt/intel/sgxsdk/environment
|
with:
|
||||||
attempts=0
|
command: |
|
||||||
max_attempts=3
|
cd ./tests/wamr-test-suites
|
||||||
|
source /opt/intel/sgxsdk/environment
|
||||||
while [ $attempts -lt $max_attempts ]; do
|
|
||||||
./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
|
./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
|
||||||
exitcode="$?"
|
max_attempts: 3
|
||||||
|
retry_on: error
|
||||||
|
shell: bash
|
||||||
|
timeout_minutes: 10
|
||||||
|
|
||||||
if [ $exitcode -eq 0 ]; then
|
- name: print test results
|
||||||
echo "Spec test passed"
|
run: |
|
||||||
exit 0
|
echo "Test results:"
|
||||||
elif [ $exitcode -ne 143 ]; then
|
echo "${{ steps.run_spec_tests.outputs.stdout }}"
|
||||||
echo "Spec test failed with error code $exitcode"
|
echo "${{ steps.run_spec_tests.outputs.stderr }}"
|
||||||
exit 1
|
echo "Exit code: ${{ steps.run_spec_tests.outputs.exit_code }}"
|
||||||
fi
|
echo "Exit error: ${{ steps.run_spec_tests.outputs.exit_error }}"
|
||||||
|
shell: bash
|
||||||
echo "$exitcode is a known GitHub-hosted runner issue"
|
|
||||||
echo "::notice::Re-running the spec test due to error code 143"
|
|
||||||
attempts=$((attempts + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "::notice::Report an error with code 143 in SGX CI after $max_attempts attempts"
|
|
||||||
exit 143
|
|
||||||
working-directory: ./tests/wamr-test-suites
|
|
||||||
|
|
86
.github/workflows/compilation_on_windows.yml
vendored
86
.github/workflows/compilation_on_windows.yml
vendored
|
@ -57,23 +57,33 @@ permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build_llvm_libraries_on_windows:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: write
|
||||||
|
uses: ./.github/workflows/build_llvm_libraries.yml
|
||||||
|
with:
|
||||||
|
os: "windows-latest"
|
||||||
|
arch: "AArch64 ARM Mips RISCV X86"
|
||||||
|
|
||||||
|
build_iwasm:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
build_options: [
|
build_options:
|
||||||
"-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0",
|
[
|
||||||
"-DWAMR_BUILD_AOT=0",
|
"-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0",
|
||||||
"-DWAMR_BUILD_TAIL_CALL=1",
|
"-DWAMR_BUILD_AOT=0",
|
||||||
"-DWAMR_BUILD_CUSTOM_NAME_SECTION=1",
|
"-DWAMR_BUILD_TAIL_CALL=1",
|
||||||
"-DWAMR_DISABLE_HW_BOUND_CHECK=1",
|
"-DWAMR_BUILD_CUSTOM_NAME_SECTION=1",
|
||||||
"-DWAMR_BUILD_REF_TYPES=1",
|
"-DWAMR_DISABLE_HW_BOUND_CHECK=1",
|
||||||
"-DWAMR_BUILD_SIMD=1",
|
"-DWAMR_BUILD_REF_TYPES=1",
|
||||||
"-DWAMR_BUILD_DEBUG_INTERP=1",
|
"-DWAMR_BUILD_SIMD=1",
|
||||||
"-DWAMR_BUILD_LIB_PTHREAD=1",
|
"-DWAMR_BUILD_DEBUG_INTERP=1",
|
||||||
"-DWAMR_BUILD_LIB_WASI_THREADS=1",
|
"-DWAMR_BUILD_LIB_PTHREAD=1",
|
||||||
"-DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1"
|
"-DWAMR_BUILD_LIB_WASI_THREADS=1",
|
||||||
]
|
"-DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1",
|
||||||
|
]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
@ -89,17 +99,49 @@ jobs:
|
||||||
cmake .. ${{ matrix.build_options }}
|
cmake .. ${{ matrix.build_options }}
|
||||||
cmake --build . --config Release --parallel 4
|
cmake --build . --config Release --parallel 4
|
||||||
|
|
||||||
|
build_wamrc:
|
||||||
|
needs: [build_llvm_libraries_on_windows]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
llvm_cache_key: ${{ needs.build_llvm_libraries_on_windows.outputs.cache_key }}
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# since jobs.id can't contain the dot character
|
||||||
|
# it is hard to use `format` to assemble the cache key
|
||||||
|
- name: Get LLVM libraries
|
||||||
|
id: retrieve_llvm_libs
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
./core/deps/llvm/build/bin
|
||||||
|
./core/deps/llvm/build/include
|
||||||
|
./core/deps/llvm/build/lib
|
||||||
|
./core/deps/llvm/build/libexec
|
||||||
|
./core/deps/llvm/build/share
|
||||||
|
key: ${{ matrix.llvm_cache_key }}
|
||||||
|
|
||||||
|
- name: Quit if cache miss
|
||||||
|
if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true'
|
||||||
|
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
|
||||||
|
|
||||||
|
- name: Build wamrc
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build
|
||||||
|
cmake --build build --config Release --parallel 4
|
||||||
|
working-directory: wamr-compiler
|
||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
needs: [build]
|
needs: [build_iwasm, build_wamrc]
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
running_mode:
|
running_mode: ["classic-interp", "fast-interp"]
|
||||||
[
|
|
||||||
"classic-interp",
|
|
||||||
"fast-interp",
|
|
||||||
]
|
|
||||||
test_option:
|
test_option:
|
||||||
[
|
[
|
||||||
$DEFAULT_TEST_OPTIONS,
|
$DEFAULT_TEST_OPTIONS,
|
||||||
|
@ -130,6 +172,10 @@ jobs:
|
||||||
run: ./build.sh
|
run: ./build.sh
|
||||||
working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/
|
working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/
|
||||||
|
|
||||||
|
- name: install wget
|
||||||
|
shell: bash
|
||||||
|
run: choco install wget
|
||||||
|
|
||||||
- name: run tests
|
- name: run tests
|
||||||
shell: bash
|
shell: bash
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
|
|
46
.github/workflows/nightly_run.yml
vendored
46
.github/workflows/nightly_run.yml
vendored
|
@ -36,12 +36,11 @@ env:
|
||||||
LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
|
LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
|
||||||
MULTI_TIER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
|
MULTI_TIER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
|
||||||
# For Spec Test
|
# For Spec Test
|
||||||
# FIXME: use binary release(adding -b) instead of building from source after upgrading to 22.04
|
DEFAULT_TEST_OPTIONS: "-s spec -b -P"
|
||||||
DEFAULT_TEST_OPTIONS: "-s spec -P"
|
MULTI_MODULES_TEST_OPTIONS: "-s spec -b -P -M"
|
||||||
MULTI_MODULES_TEST_OPTIONS: "-s spec -M -P"
|
SIMD_TEST_OPTIONS: "-s spec -b -P -S"
|
||||||
SIMD_TEST_OPTIONS: "-s spec -S -P"
|
THREADS_TEST_OPTIONS: "-s spec -b -P -p"
|
||||||
THREADS_TEST_OPTIONS: "-s spec -p -P"
|
X86_32_TARGET_TEST_OPTIONS: "-m x86_32"
|
||||||
X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
|
|
||||||
WASI_TEST_OPTIONS: "-s wasi_certification -w"
|
WASI_TEST_OPTIONS: "-s wasi_certification -w"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
@ -617,42 +616,21 @@ jobs:
|
||||||
sanitizer: tsan
|
sanitizer: tsan
|
||||||
- running_mode: "multi-tier-jit"
|
- running_mode: "multi-tier-jit"
|
||||||
sanitizer: tsan
|
sanitizer: tsan
|
||||||
# classic-interp and fast-interp don't support simd
|
# simd128.h brings ubsan errors
|
||||||
- running_mode: "classic-interp"
|
# like: negation of XXXcannot be represented in type 'long int';
|
||||||
test_option: $SIMD_TEST_OPTIONS
|
# cast to an unsigned type to negate this value to itself
|
||||||
- running_mode: "fast-interp"
|
- running_mode: "fast-interp"
|
||||||
test_option: $SIMD_TEST_OPTIONS
|
sanitizer: ubsan
|
||||||
# llvm jit doesn't support multi module
|
|
||||||
- running_mode: "jit"
|
|
||||||
test_option: $MULTI_MODULES_TEST_OPTIONS
|
|
||||||
# fast-jit doesn't support multi module, simd
|
|
||||||
- running_mode: "fast-jit"
|
|
||||||
test_option: $MULTI_MODULES_TEST_OPTIONS
|
|
||||||
- running_mode: "fast-jit"
|
|
||||||
test_option: $SIMD_TEST_OPTIONS
|
|
||||||
# multi-tier-jit doesn't support multi module, simd
|
|
||||||
- running_mode: "multi-tier-jit"
|
|
||||||
test_option: $MULTI_MODULES_TEST_OPTIONS
|
|
||||||
- running_mode: "multi-tier-jit"
|
|
||||||
test_option: $SIMD_TEST_OPTIONS
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: install-wasi-sdk-wabt
|
- name: install-wasi-sdk-wabt
|
||||||
|
if: matrix.test_option == '$WASI_TEST_OPTIONS'
|
||||||
uses: ./.github/actions/install-wasi-sdk-wabt
|
uses: ./.github/actions/install-wasi-sdk-wabt
|
||||||
with:
|
with:
|
||||||
os: ${{ matrix.os }}
|
os: ${{ matrix.os }}
|
||||||
|
|
||||||
# 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: |
|
|
||||||
git clone https://github.com/WebAssembly/wasi-libc
|
|
||||||
cd wasi-libc
|
|
||||||
make -j AR=/opt/wasi-sdk/bin/llvm-ar NM=/opt/wasi-sdk/bin/llvm-nm CC=/opt/wasi-sdk/bin/clang THREAD_MODEL=posix
|
|
||||||
echo "SYSROOT_PATH=$PWD/sysroot" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: set env variable(if llvm are used)
|
- name: set env variable(if llvm are used)
|
||||||
if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit' || matrix.running_mode == 'multi-tier-jit'
|
if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit' || matrix.running_mode == 'multi-tier-jit'
|
||||||
run: echo "USE_LLVM=true" >> $GITHUB_ENV
|
run: echo "USE_LLVM=true" >> $GITHUB_ENV
|
||||||
|
@ -697,12 +675,12 @@ jobs:
|
||||||
|
|
||||||
- name: Build WASI thread tests
|
- name: Build WASI thread tests
|
||||||
if: matrix.test_option == '$WASI_TEST_OPTIONS'
|
if: matrix.test_option == '$WASI_TEST_OPTIONS'
|
||||||
run: bash build.sh --sysroot "$SYSROOT_PATH"
|
run: bash build.sh
|
||||||
working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/
|
working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/
|
||||||
|
|
||||||
- name: Build WASI thread stress tests
|
- name: Build WASI thread stress tests
|
||||||
if: matrix.test_option == '$WASI_TEST_OPTIONS'
|
if: matrix.test_option == '$WASI_TEST_OPTIONS'
|
||||||
run: bash build.sh --sysroot "$SYSROOT_PATH"
|
run: bash build.sh
|
||||||
working-directory: ./core/iwasm/libraries/lib-wasi-threads/stress-test/
|
working-directory: ./core/iwasm/libraries/lib-wasi-threads/stress-test/
|
||||||
|
|
||||||
- name: build socket api tests
|
- name: build socket api tests
|
||||||
|
|
4
.github/workflows/supply_chain.yml
vendored
4
.github/workflows/supply_chain.yml
vendored
|
@ -39,7 +39,7 @@ jobs:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Run analysis"
|
- name: "Run analysis"
|
||||||
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
|
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
||||||
with:
|
with:
|
||||||
results_file: results.sarif
|
results_file: results.sarif
|
||||||
results_format: sarif
|
results_format: sarif
|
||||||
|
@ -60,6 +60,6 @@ jobs:
|
||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@57eebf61a2246ab60a0c2f5a85766db783ad3553
|
uses: github/codeql-action/upload-sarif@2847b7f7ab9f48fc49eca90a53fff6007285f399
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|
|
@ -99,9 +99,9 @@ if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS)
|
||||||
set (WAMR_BUILD_LIB_WASI_THREADS 0)
|
set (WAMR_BUILD_LIB_WASI_THREADS 0)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (NOT DEFINED WAMR_ENABLE_COPY_CALLSTACK)
|
if (NOT DEFINED WAMR_BUILD_COPY_CALL_STACK)
|
||||||
# Disable copy callstack by default
|
# Disable copy callstack by default
|
||||||
set (WAMR_ENABLE_COPY_CALLSTACK 0)
|
set (WAMR_BUILD_COPY_CALL_STACK 0)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT DEFINED WAMR_BUILD_MINI_LOADER)
|
if (NOT DEFINED WAMR_BUILD_MINI_LOADER)
|
||||||
|
|
|
@ -21,7 +21,7 @@ WebAssembly Micro Runtime (WAMR) is a lightweight standalone WebAssembly (Wasm)
|
||||||
|
|
||||||
### Key features
|
### Key features
|
||||||
- Full compliant to the W3C Wasm MVP
|
- Full compliant to the W3C Wasm MVP
|
||||||
- Small runtime binary size (core vmlib on cortex-m4f with tail-call/bulk memroy/shared memroy support, text size from bloaty)
|
- Small runtime binary size (core vmlib on cortex-m4f with tail-call/bulk memory/shared memory support, text size from bloaty)
|
||||||
* ~58.9K for fast interpreter
|
* ~58.9K for fast interpreter
|
||||||
* ~56.3K for classic interpreter
|
* ~56.3K for classic interpreter
|
||||||
* ~29.4K for aot runtime
|
* ~29.4K for aot runtime
|
||||||
|
|
|
@ -1,3 +1,35 @@
|
||||||
|
## WAMR-2.3.1
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- Revert the location to install public headers (#4295). This restores compatibility (of installed headers) with WAMR-2.2.0 and earlier.
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
- feat: Add instruction metering for interpreter (#4122)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- updating WASI stdio handle initialization and build options for UVWASI (#4260)
|
||||||
|
- Fix SIMD load lane to avoid incompatible pointer types (#4278)
|
||||||
|
- Fixed unit tests on X86_32 (#4279)
|
||||||
|
- Improve Embedding WAMR guideline (#4284)
|
||||||
|
- Fix Compiler Error C2491 (#4286)
|
||||||
|
- Enhance type checking for function types in loader and improve error handling (#4294)
|
||||||
|
- Dockerfile.vx-delegate build error fix (#4273)
|
||||||
|
- Enable runtime API exposure for MSVC builds (#4287)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
- feat(yml): Add ESP32-P4 and ESP32-C5 support (#4270)
|
||||||
|
- add a sample to use cmake package (#4291)
|
||||||
|
|
||||||
|
### Others
|
||||||
|
|
||||||
|
- build(deps): Bump github/codeql-action from 3.28.17 to 3.28.18 (#4285)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## WAMR-2.3.0
|
## WAMR-2.3.0
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
|
@ -465,7 +497,7 @@
|
||||||
- wasm loader: Fix handling if block without op else (#3404)
|
- wasm loader: Fix handling if block without op else (#3404)
|
||||||
- ref-types: Correct default value for function local variables (#3397)
|
- ref-types: Correct default value for function local variables (#3397)
|
||||||
- aot compiler: Fix the length type passed to aot_memmove/aot_memset (#3378)
|
- aot compiler: Fix the length type passed to aot_memmove/aot_memset (#3378)
|
||||||
- Fix loader and mini-loader select potiential error (#3374)
|
- Fix loader and mini-loader select potential error (#3374)
|
||||||
- Fix aot debugger compilation error on windows (#3370)
|
- Fix aot debugger compilation error on windows (#3370)
|
||||||
- A few native stack detection fixes for macOS/arm64 (#3368)
|
- A few native stack detection fixes for macOS/arm64 (#3368)
|
||||||
- Fix ESP32-S3 compiling error (#3359)
|
- Fix ESP32-S3 compiling error (#3359)
|
||||||
|
|
|
@ -334,15 +334,10 @@ if (WAMR_BUILD_SHARED_HEAP EQUAL 1)
|
||||||
add_definitions (-DWASM_ENABLE_SHARED_HEAP=1)
|
add_definitions (-DWASM_ENABLE_SHARED_HEAP=1)
|
||||||
message (" Shared heap enabled")
|
message (" Shared heap enabled")
|
||||||
endif()
|
endif()
|
||||||
|
if (WAMR_BUILD_COPY_CALL_STACK EQUAL 1)
|
||||||
if (WAMR_ENABLE_COPY_CALLSTACK EQUAL 1)
|
add_definitions (-DWASM_ENABLE_COPY_CALL_STACK=1)
|
||||||
add_definitions (-DWAMR_ENABLE_COPY_CALLSTACK=1)
|
|
||||||
message(" Copy callstack enabled")
|
message(" Copy callstack enabled")
|
||||||
else ()
|
|
||||||
add_definitions (-DWAMR_ENABLE_COPY_CALLSTACK=0)
|
|
||||||
message(" Copy callstack disabled")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WAMR_BUILD_MEMORY64 EQUAL 1)
|
if (WAMR_BUILD_MEMORY64 EQUAL 1)
|
||||||
# if native is 32-bit or cross-compiled to 32-bit
|
# if native is 32-bit or cross-compiled to 32-bit
|
||||||
if (NOT WAMR_BUILD_TARGET MATCHES ".*64.*")
|
if (NOT WAMR_BUILD_TARGET MATCHES ".*64.*")
|
||||||
|
@ -539,6 +534,9 @@ if (WAMR_BUILD_WASI_NN EQUAL 1)
|
||||||
if (DEFINED WAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH)
|
if (DEFINED WAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH)
|
||||||
add_definitions (-DWASM_WASI_NN_EXTERNAL_DELEGATE_PATH="${WAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH}")
|
add_definitions (-DWASM_WASI_NN_EXTERNAL_DELEGATE_PATH="${WAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH}")
|
||||||
endif ()
|
endif ()
|
||||||
|
if (NOT DEFINED WAMR_BUILD_WASI_EPHEMERAL_NN)
|
||||||
|
set(WAMR_BUILD_WASI_EPHEMERAL_NN 1)
|
||||||
|
endif()
|
||||||
if (WAMR_BUILD_WASI_EPHEMERAL_NN EQUAL 1)
|
if (WAMR_BUILD_WASI_EPHEMERAL_NN EQUAL 1)
|
||||||
message (" WASI-NN: use 'wasi_ephemeral_nn' instead of 'wasi-nn'")
|
message (" WASI-NN: use 'wasi_ephemeral_nn' instead of 'wasi-nn'")
|
||||||
add_definitions (-DWASM_ENABLE_WASI_EPHEMERAL_NN=1)
|
add_definitions (-DWASM_ENABLE_WASI_EPHEMERAL_NN=1)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
requests==2.32.3
|
requests==2.32.4
|
|
@ -106,6 +106,7 @@ endif ()
|
||||||
|
|
||||||
if (WAMR_BUILD_WASI_NN EQUAL 1)
|
if (WAMR_BUILD_WASI_NN EQUAL 1)
|
||||||
include (${IWASM_DIR}/libraries/wasi-nn/cmake/wasi_nn.cmake)
|
include (${IWASM_DIR}/libraries/wasi-nn/cmake/wasi_nn.cmake)
|
||||||
|
set (WAMR_BUILD_MODULE_INST_CONTEXT 1)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
|
if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
|
||||||
|
|
|
@ -8,7 +8,7 @@ endif()
|
||||||
|
|
||||||
set(WAMR_VERSION_MAJOR 2)
|
set(WAMR_VERSION_MAJOR 2)
|
||||||
set(WAMR_VERSION_MINOR 3)
|
set(WAMR_VERSION_MINOR 3)
|
||||||
set(WAMR_VERSION_PATCH 0)
|
set(WAMR_VERSION_PATCH 1)
|
||||||
|
|
||||||
message("-- WAMR version: ${WAMR_VERSION_MAJOR}.${WAMR_VERSION_MINOR}.${WAMR_VERSION_PATCH}")
|
message("-- WAMR version: ${WAMR_VERSION_MAJOR}.${WAMR_VERSION_MINOR}.${WAMR_VERSION_PATCH}")
|
||||||
|
|
||||||
|
|
|
@ -193,8 +193,8 @@
|
||||||
#error "Heap aux stack allocation must be enabled for WASI threads"
|
#error "Heap aux stack allocation must be enabled for WASI threads"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef WAMR_ENABLE_COPY_CALLSTACK
|
#ifndef WASM_ENABLE_COPY_CALL_STACK
|
||||||
#define WAMR_ENABLE_COPY_CALLSTACK 0
|
#define WASM_ENABLE_COPY_CALL_STACK 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef WASM_ENABLE_BASE_LIB
|
#ifndef WASM_ENABLE_BASE_LIB
|
||||||
|
|
|
@ -1309,6 +1309,13 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
|
||||||
read_uint32(buf, buf_end, type_idx);
|
read_uint32(buf, buf_end, type_idx);
|
||||||
read_uint32(buf, buf_end, length);
|
read_uint32(buf, buf_end, length);
|
||||||
|
|
||||||
|
if (type_idx >= module->type_count
|
||||||
|
|| !wasm_type_is_array_type(module->types[type_idx])) {
|
||||||
|
set_error_buf(error_buf, error_buf_size,
|
||||||
|
"invalid or non-array type index.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT) {
|
if (init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT) {
|
||||||
expr->u.array_new_default.type_index = type_idx;
|
expr->u.array_new_default.type_index = type_idx;
|
||||||
expr->u.array_new_default.length = length;
|
expr->u.array_new_default.length = length;
|
||||||
|
@ -1723,6 +1730,12 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
|
||||||
(void)u8;
|
(void)u8;
|
||||||
|
|
||||||
read_uint32(buf, buf_end, j);
|
read_uint32(buf, buf_end, j);
|
||||||
|
#if WASM_ENABLE_AOT_VALIDATOR != 0
|
||||||
|
if (j >= module->type_count) {
|
||||||
|
set_error_buf(error_buf, error_buf_size, "invalid type index");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (module->types[j]->ref_count == UINT16_MAX) {
|
if (module->types[j]->ref_count == UINT16_MAX) {
|
||||||
set_error_buf(error_buf, error_buf_size,
|
set_error_buf(error_buf, error_buf_size,
|
||||||
"wasm type's ref count too large");
|
"wasm type's ref count too large");
|
||||||
|
@ -1986,6 +1999,13 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
|
||||||
AOTType *cur_type = module->types[j];
|
AOTType *cur_type = module->types[j];
|
||||||
parent_type_idx = cur_type->parent_type_idx;
|
parent_type_idx = cur_type->parent_type_idx;
|
||||||
if (parent_type_idx != (uint32)-1) { /* has parent */
|
if (parent_type_idx != (uint32)-1) { /* has parent */
|
||||||
|
#if WASM_ENABLE_AOT_VALIDATOR != 0
|
||||||
|
if (parent_type_idx >= module->type_count) {
|
||||||
|
set_error_buf(error_buf, error_buf_size,
|
||||||
|
"invalid parent type index");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
AOTType *parent_type = module->types[parent_type_idx];
|
AOTType *parent_type = module->types[parent_type_idx];
|
||||||
|
|
||||||
module->types[j]->parent_type = parent_type;
|
module->types[j]->parent_type = parent_type;
|
||||||
|
@ -2009,6 +2029,13 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
|
||||||
AOTType *cur_type = module->types[j];
|
AOTType *cur_type = module->types[j];
|
||||||
parent_type_idx = cur_type->parent_type_idx;
|
parent_type_idx = cur_type->parent_type_idx;
|
||||||
if (parent_type_idx != (uint32)-1) { /* has parent */
|
if (parent_type_idx != (uint32)-1) { /* has parent */
|
||||||
|
#if WASM_ENABLE_AOT_VALIDATOR != 0
|
||||||
|
if (parent_type_idx >= module->type_count) {
|
||||||
|
set_error_buf(error_buf, error_buf_size,
|
||||||
|
"invalid parent type index");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
AOTType *parent_type = module->types[parent_type_idx];
|
AOTType *parent_type = module->types[parent_type_idx];
|
||||||
/* subtyping has been checked during compilation */
|
/* subtyping has been checked during compilation */
|
||||||
bh_assert(wasm_type_is_subtype_of(
|
bh_assert(wasm_type_is_subtype_of(
|
||||||
|
@ -3323,7 +3350,7 @@ do_data_relocation(AOTModule *module, AOTRelocationGroup *group,
|
||||||
uint8 *data_addr;
|
uint8 *data_addr;
|
||||||
uint32 data_size = 0, i;
|
uint32 data_size = 0, i;
|
||||||
AOTRelocation *relocation = group->relocations;
|
AOTRelocation *relocation = group->relocations;
|
||||||
void *symbol_addr;
|
void *symbol_addr = NULL;
|
||||||
char *symbol, *data_section_name;
|
char *symbol, *data_section_name;
|
||||||
|
|
||||||
if (!strncmp(group->section_name, ".rela.", 6)) {
|
if (!strncmp(group->section_name, ".rela.", 6)) {
|
||||||
|
|
|
@ -4137,9 +4137,9 @@ aot_frame_update_profile_info(WASMExecEnv *exec_env, bool alloc_frame)
|
||||||
}
|
}
|
||||||
#endif /* end of WASM_ENABLE_AOT_STACK_FRAME != 0 */
|
#endif /* end of WASM_ENABLE_AOT_STACK_FRAME != 0 */
|
||||||
|
|
||||||
#if WAMR_ENABLE_COPY_CALLSTACK != 0
|
#if WASM_ENABLE_COPY_CALL_STACK != 0
|
||||||
uint32
|
uint32
|
||||||
aot_copy_callstack_tiny_frame(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
aot_copy_callstack_tiny_frame(WASMExecEnv *exec_env, WASMCApiFrame *buffer,
|
||||||
const uint32 length, const uint32 skip_n,
|
const uint32 length, const uint32 skip_n,
|
||||||
char *error_buf, uint32 error_buf_size)
|
char *error_buf, uint32 error_buf_size)
|
||||||
{
|
{
|
||||||
|
@ -4193,7 +4193,7 @@ aot_copy_callstack_tiny_frame(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32
|
uint32
|
||||||
aot_copy_callstack_standard_frame(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
aot_copy_callstack_standard_frame(WASMExecEnv *exec_env, WASMCApiFrame *buffer,
|
||||||
const uint32 length, const uint32 skip_n,
|
const uint32 length, const uint32 skip_n,
|
||||||
char *error_buf, uint32_t error_buf_size)
|
char *error_buf, uint32_t error_buf_size)
|
||||||
{
|
{
|
||||||
|
@ -4243,7 +4243,7 @@ aot_copy_callstack_standard_frame(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32
|
uint32
|
||||||
aot_copy_callstack(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
aot_copy_callstack(WASMExecEnv *exec_env, WASMCApiFrame *buffer,
|
||||||
const uint32 length, const uint32 skip_n, char *error_buf,
|
const uint32 length, const uint32 skip_n, char *error_buf,
|
||||||
uint32_t error_buf_size)
|
uint32_t error_buf_size)
|
||||||
{
|
{
|
||||||
|
@ -4265,7 +4265,7 @@ aot_copy_callstack(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
||||||
error_buf, error_buf_size);
|
error_buf, error_buf_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // WAMR_ENABLE_COPY_CALLSTACK
|
#endif // WASM_ENABLE_COPY_CALL_STACK
|
||||||
|
|
||||||
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
||||||
bool
|
bool
|
||||||
|
@ -4877,8 +4877,8 @@ aot_dump_pgo_prof_data_to_buf(AOTModuleInstance *module_inst, char *buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
prof_header.magic = 0xFF6C70726F667281LL;
|
prof_header.magic = 0xFF6C70726F667281LL;
|
||||||
/* Version 8 */
|
/* Version 9 */
|
||||||
prof_header.version = 0x0000000000000008LL;
|
prof_header.version = 0x0000000000000009LL;
|
||||||
/* with VARIANT_MASK_IR_PROF (IR Instrumentation) */
|
/* with VARIANT_MASK_IR_PROF (IR Instrumentation) */
|
||||||
prof_header.version |= 0x1ULL << 56;
|
prof_header.version |= 0x1ULL << 56;
|
||||||
/* with VARIANT_MASK_MEMPROF (Memory Profile) */
|
/* with VARIANT_MASK_MEMPROF (Memory Profile) */
|
||||||
|
@ -4887,14 +4887,19 @@ aot_dump_pgo_prof_data_to_buf(AOTModuleInstance *module_inst, char *buf,
|
||||||
prof_header.num_prof_counters = num_prof_counters;
|
prof_header.num_prof_counters = num_prof_counters;
|
||||||
prof_header.names_size = prof_names_size;
|
prof_header.names_size = prof_names_size;
|
||||||
prof_header.value_kind_last = 1;
|
prof_header.value_kind_last = 1;
|
||||||
|
/* __llvm_prf_bits won't be used in PGO, set dummy value here */
|
||||||
|
prof_header.num_prof_bitmaps = 0;
|
||||||
|
prof_header.bitmap_delta = 0;
|
||||||
|
|
||||||
if (!is_little_endian()) {
|
if (!is_little_endian()) {
|
||||||
aot_exchange_uint64((uint8 *)&prof_header.magic);
|
aot_exchange_uint64((uint8 *)&prof_header.magic);
|
||||||
aot_exchange_uint64((uint8 *)&prof_header.version);
|
aot_exchange_uint64((uint8 *)&prof_header.version);
|
||||||
aot_exchange_uint64((uint8 *)&prof_header.num_prof_data);
|
aot_exchange_uint64((uint8 *)&prof_header.num_prof_data);
|
||||||
aot_exchange_uint64((uint8 *)&prof_header.num_prof_counters);
|
aot_exchange_uint64((uint8 *)&prof_header.num_prof_counters);
|
||||||
|
aot_exchange_uint64((uint8 *)&prof_header.num_prof_bitmaps);
|
||||||
aot_exchange_uint64((uint8 *)&prof_header.names_size);
|
aot_exchange_uint64((uint8 *)&prof_header.names_size);
|
||||||
aot_exchange_uint64((uint8 *)&prof_header.counters_delta);
|
aot_exchange_uint64((uint8 *)&prof_header.counters_delta);
|
||||||
|
aot_exchange_uint64((uint8 *)&prof_header.bitmap_delta);
|
||||||
aot_exchange_uint64((uint8 *)&prof_header.value_kind_last);
|
aot_exchange_uint64((uint8 *)&prof_header.value_kind_last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4912,19 +4917,23 @@ aot_dump_pgo_prof_data_to_buf(AOTModuleInstance *module_inst, char *buf,
|
||||||
prof_data_64->func_md5 = prof_data->func_md5;
|
prof_data_64->func_md5 = prof_data->func_md5;
|
||||||
prof_data_64->func_hash = prof_data->func_hash;
|
prof_data_64->func_hash = prof_data->func_hash;
|
||||||
prof_data_64->offset_counters = prof_data->offset_counters;
|
prof_data_64->offset_counters = prof_data->offset_counters;
|
||||||
|
prof_data_64->offset_bitmaps = prof_data->offset_bitmaps;
|
||||||
prof_data_64->func_ptr = prof_data->func_ptr;
|
prof_data_64->func_ptr = prof_data->func_ptr;
|
||||||
prof_data_64->values = (uint64)(uintptr_t)prof_data->values;
|
prof_data_64->values = (uint64)(uintptr_t)prof_data->values;
|
||||||
prof_data_64->num_counters = prof_data->num_counters;
|
prof_data_64->num_counters = prof_data->num_counters;
|
||||||
|
/* __llvm_prf_bits won't be used in PGO, set dummy value here */
|
||||||
|
prof_data_64->num_bitmaps = 0;
|
||||||
prof_data_64->num_value_sites[0] = prof_data->num_value_sites[0];
|
prof_data_64->num_value_sites[0] = prof_data->num_value_sites[0];
|
||||||
prof_data_64->num_value_sites[1] = prof_data->num_value_sites[1];
|
prof_data_64->num_value_sites[1] = prof_data->num_value_sites[1];
|
||||||
|
|
||||||
if (!is_little_endian()) {
|
if (!is_little_endian()) {
|
||||||
aot_exchange_uint64((uint8 *)&prof_data_64->func_hash);
|
aot_exchange_uint64((uint8 *)&prof_data_64->func_hash);
|
||||||
aot_exchange_uint64((uint8 *)&prof_data_64->offset_counters);
|
aot_exchange_uint64((uint8 *)&prof_data_64->offset_counters);
|
||||||
aot_exchange_uint64((uint8 *)&prof_data_64->offset_counters);
|
aot_exchange_uint64((uint8 *)&prof_data_64->offset_bitmaps);
|
||||||
aot_exchange_uint64((uint8 *)&prof_data_64->func_ptr);
|
aot_exchange_uint64((uint8 *)&prof_data_64->func_ptr);
|
||||||
aot_exchange_uint64((uint8 *)&prof_data_64->values);
|
aot_exchange_uint64((uint8 *)&prof_data_64->values);
|
||||||
aot_exchange_uint32((uint8 *)&prof_data_64->num_counters);
|
aot_exchange_uint32((uint8 *)&prof_data_64->num_counters);
|
||||||
|
aot_exchange_uint32((uint8 *)&prof_data_64->num_bitmaps);
|
||||||
aot_exchange_uint16((uint8 *)&prof_data_64->num_value_sites[0]);
|
aot_exchange_uint16((uint8 *)&prof_data_64->num_value_sites[0]);
|
||||||
aot_exchange_uint16((uint8 *)&prof_data_64->num_value_sites[1]);
|
aot_exchange_uint16((uint8 *)&prof_data_64->num_value_sites[1]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -437,6 +437,9 @@ typedef struct AOTFrame {
|
||||||
} AOTFrame;
|
} AOTFrame;
|
||||||
|
|
||||||
#if WASM_ENABLE_STATIC_PGO != 0
|
#if WASM_ENABLE_STATIC_PGO != 0
|
||||||
|
/* The bitmaps fields in LLVMProfileRawHeader, LLVMProfileData,
|
||||||
|
* LLVMProfileData_64 all dummy fields, it's used in MC/DC code coverage
|
||||||
|
* instead of PGO. See https://llvm.org/docs/InstrProfileFormat.html#bitmap */
|
||||||
typedef struct LLVMProfileRawHeader {
|
typedef struct LLVMProfileRawHeader {
|
||||||
uint64 magic;
|
uint64 magic;
|
||||||
uint64 version;
|
uint64 version;
|
||||||
|
@ -445,8 +448,11 @@ typedef struct LLVMProfileRawHeader {
|
||||||
uint64 padding_bytes_before_counters;
|
uint64 padding_bytes_before_counters;
|
||||||
uint64 num_prof_counters;
|
uint64 num_prof_counters;
|
||||||
uint64 padding_bytes_after_counters;
|
uint64 padding_bytes_after_counters;
|
||||||
|
uint64 num_prof_bitmaps;
|
||||||
|
uint64 padding_bytes_after_bitmaps;
|
||||||
uint64 names_size;
|
uint64 names_size;
|
||||||
uint64 counters_delta;
|
uint64 counters_delta;
|
||||||
|
uint64 bitmap_delta;
|
||||||
uint64 names_delta;
|
uint64 names_delta;
|
||||||
uint64 value_kind_last;
|
uint64 value_kind_last;
|
||||||
} LLVMProfileRawHeader;
|
} LLVMProfileRawHeader;
|
||||||
|
@ -464,10 +470,12 @@ typedef struct LLVMProfileData {
|
||||||
uint64 func_md5;
|
uint64 func_md5;
|
||||||
uint64 func_hash;
|
uint64 func_hash;
|
||||||
uint64 offset_counters;
|
uint64 offset_counters;
|
||||||
|
uint64 offset_bitmaps;
|
||||||
uintptr_t func_ptr;
|
uintptr_t func_ptr;
|
||||||
ValueProfNode **values;
|
ValueProfNode **values;
|
||||||
uint32 num_counters;
|
uint32 num_counters;
|
||||||
uint16 num_value_sites[2];
|
uint16 num_value_sites[2];
|
||||||
|
uint32 num_bitmaps;
|
||||||
} LLVMProfileData;
|
} LLVMProfileData;
|
||||||
|
|
||||||
/* The profiling data for writing to the output file, the width of
|
/* The profiling data for writing to the output file, the width of
|
||||||
|
@ -477,10 +485,12 @@ typedef struct LLVMProfileData_64 {
|
||||||
uint64 func_md5;
|
uint64 func_md5;
|
||||||
uint64 func_hash;
|
uint64 func_hash;
|
||||||
uint64 offset_counters;
|
uint64 offset_counters;
|
||||||
|
uint64 offset_bitmaps;
|
||||||
uint64 func_ptr;
|
uint64 func_ptr;
|
||||||
uint64 values;
|
uint64 values;
|
||||||
uint32 num_counters;
|
uint32 num_counters;
|
||||||
uint16 num_value_sites[2];
|
uint16 num_value_sites[2];
|
||||||
|
uint32 num_bitmaps;
|
||||||
} LLVMProfileData_64;
|
} LLVMProfileData_64;
|
||||||
#endif /* end of WASM_ENABLE_STATIC_PGO != 0 */
|
#endif /* end of WASM_ENABLE_STATIC_PGO != 0 */
|
||||||
|
|
||||||
|
@ -777,12 +787,12 @@ aot_frame_update_profile_info(WASMExecEnv *exec_env, bool alloc_frame);
|
||||||
bool
|
bool
|
||||||
aot_create_call_stack(struct WASMExecEnv *exec_env);
|
aot_create_call_stack(struct WASMExecEnv *exec_env);
|
||||||
|
|
||||||
#if WAMR_ENABLE_COPY_CALLSTACK != 0
|
#if WASM_ENABLE_COPY_CALL_STACK != 0
|
||||||
uint32
|
uint32
|
||||||
aot_copy_callstack(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
aot_copy_callstack(WASMExecEnv *exec_env, WASMCApiFrame *buffer,
|
||||||
const uint32 length, const uint32 skip_n, char *error_buf,
|
const uint32 length, const uint32 skip_n, char *error_buf,
|
||||||
uint32_t error_buf_size);
|
uint32_t error_buf_size);
|
||||||
#endif // WAMR_ENABLE_COPY_CALLSTACK
|
#endif // WASM_ENABLE_COPY_CALL_STACK
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Dump wasm call stack or get the size
|
* @brief Dump wasm call stack or get the size
|
||||||
|
|
|
@ -1145,7 +1145,7 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1,
|
||||||
return true;
|
return true;
|
||||||
else {
|
else {
|
||||||
int32 heap_type = ref_type1->ref_ht_common.heap_type;
|
int32 heap_type = ref_type1->ref_ht_common.heap_type;
|
||||||
// We dont care whether type2 is nullable or not. So
|
// We don't care whether type2 is nullable or not. So
|
||||||
// we normalize it into its related one-byte type.
|
// we normalize it into its related one-byte type.
|
||||||
if (type2 == REF_TYPE_HT_NULLABLE
|
if (type2 == REF_TYPE_HT_NULLABLE
|
||||||
|| type2 == REF_TYPE_HT_NON_NULLABLE) {
|
|| type2 == REF_TYPE_HT_NON_NULLABLE) {
|
||||||
|
|
|
@ -1743,9 +1743,9 @@ wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env)
|
||||||
wasm_exec_env_destroy(exec_env);
|
wasm_exec_env_destroy(exec_env);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WAMR_ENABLE_COPY_CALLSTACK != 0
|
#if WASM_ENABLE_COPY_CALL_STACK != 0
|
||||||
uint32
|
uint32
|
||||||
wasm_copy_callstack(const wasm_exec_env_t exec_env, wasm_frame_t *buffer,
|
wasm_copy_callstack(const wasm_exec_env_t exec_env, WASMCApiFrame *buffer,
|
||||||
const uint32 length, const uint32 skip_n, char *error_buf,
|
const uint32 length, const uint32 skip_n, char *error_buf,
|
||||||
uint32_t error_buf_size)
|
uint32_t error_buf_size)
|
||||||
{
|
{
|
||||||
|
@ -1780,7 +1780,7 @@ wasm_copy_callstack(const wasm_exec_env_t exec_env, wasm_frame_t *buffer,
|
||||||
strncpy(error_buf, err_msg, error_buf_size);
|
strncpy(error_buf, err_msg, error_buf_size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // WAMR_ENABLE_COPY_CALLSTACK
|
#endif // WASM_ENABLE_COPY_CALL_STACK
|
||||||
|
|
||||||
bool
|
bool
|
||||||
wasm_runtime_init_thread_env(void)
|
wasm_runtime_init_thread_env(void)
|
||||||
|
|
|
@ -758,12 +758,12 @@ wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
|
||||||
WASM_RUNTIME_API_EXTERN void
|
WASM_RUNTIME_API_EXTERN void
|
||||||
wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env);
|
wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env);
|
||||||
|
|
||||||
#if WAMR_ENABLE_COPY_CALLSTACK != 0
|
#if WASM_ENABLE_COPY_CALL_STACK != 0
|
||||||
WASM_RUNTIME_API_EXTERN uint32_t
|
WASM_RUNTIME_API_EXTERN uint32_t
|
||||||
wasm_copy_callstack(const wasm_exec_env_t exec_env, wasm_frame_t *buffer,
|
wasm_copy_callstack(const wasm_exec_env_t exec_env, WASMCApiFrame *buffer,
|
||||||
const uint32 length, const uint32 skip_n, char *error_buf,
|
const uint32 length, const uint32 skip_n, char *error_buf,
|
||||||
uint32 error_buf_size);
|
uint32 error_buf_size);
|
||||||
#endif // WAMR_ENABLE_COPY_CALLSTACK
|
#endif // WASM_ENABLE_COPY_CALL_STACK
|
||||||
|
|
||||||
/* See wasm_export.h for description */
|
/* See wasm_export.h for description */
|
||||||
WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon *
|
WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon *
|
||||||
|
|
|
@ -999,6 +999,7 @@ static bool
|
||||||
aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||||
{
|
{
|
||||||
AOTFuncContext *func_ctx = comp_ctx->func_ctxes[func_index];
|
AOTFuncContext *func_ctx = comp_ctx->func_ctxes[func_index];
|
||||||
|
WASMModule *module = comp_ctx->comp_data->wasm_module;
|
||||||
LLVMValueRef func_index_ref;
|
LLVMValueRef func_index_ref;
|
||||||
uint8 *frame_ip = func_ctx->aot_func->code, opcode, *p_f32, *p_f64;
|
uint8 *frame_ip = func_ctx->aot_func->code, opcode, *p_f32, *p_f64;
|
||||||
uint8 *frame_ip_end = frame_ip + func_ctx->aot_func->code_size;
|
uint8 *frame_ip_end = frame_ip + func_ctx->aot_func->code_size;
|
||||||
|
@ -1230,6 +1231,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||||
read_leb_uint32(frame_ip, frame_ip_end, func_idx);
|
read_leb_uint32(frame_ip, frame_ip_end, func_idx);
|
||||||
if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, false))
|
if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, false))
|
||||||
return false;
|
return false;
|
||||||
|
if (module->functions[func_index]->has_memory_operations)
|
||||||
|
restore_memory_info(comp_ctx, func_ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1250,6 +1253,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||||
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
|
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
|
||||||
tbl_idx))
|
tbl_idx))
|
||||||
return false;
|
return false;
|
||||||
|
if (module->functions[func_index]->has_memory_operations)
|
||||||
|
restore_memory_info(comp_ctx, func_ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1427,6 +1432,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||||
if (!aot_compile_op_call_ref(comp_ctx, func_ctx, type_idx,
|
if (!aot_compile_op_call_ref(comp_ctx, func_ctx, type_idx,
|
||||||
false))
|
false))
|
||||||
return false;
|
return false;
|
||||||
|
if (module->functions[func_index]->has_memory_operations)
|
||||||
|
restore_memory_info(comp_ctx, func_ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2099,6 +2106,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
||||||
read_leb_uint32(frame_ip, frame_ip_end, mem_idx);
|
read_leb_uint32(frame_ip, frame_ip_end, mem_idx);
|
||||||
if (!aot_compile_op_memory_grow(comp_ctx, func_ctx))
|
if (!aot_compile_op_memory_grow(comp_ctx, func_ctx))
|
||||||
return false;
|
return false;
|
||||||
|
if (module->functions[func_index]->has_memory_operations)
|
||||||
|
restore_memory_info(comp_ctx, func_ctx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WASM_OP_I32_CONST:
|
case WASM_OP_I32_CONST:
|
||||||
|
|
|
@ -648,6 +648,7 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
|
||||||
#define SIZE_T_TYPE comp_ctx->basic_types.size_t_type
|
#define SIZE_T_TYPE comp_ctx->basic_types.size_t_type
|
||||||
#define MD_TYPE comp_ctx->basic_types.meta_data_type
|
#define MD_TYPE comp_ctx->basic_types.meta_data_type
|
||||||
#define INT8_PTR_TYPE comp_ctx->basic_types.int8_ptr_type
|
#define INT8_PTR_TYPE comp_ctx->basic_types.int8_ptr_type
|
||||||
|
#define INT8_PPTR_TYPE comp_ctx->basic_types.int8_pptr_type
|
||||||
#define INT16_PTR_TYPE comp_ctx->basic_types.int16_ptr_type
|
#define INT16_PTR_TYPE comp_ctx->basic_types.int16_ptr_type
|
||||||
#define INT32_PTR_TYPE comp_ctx->basic_types.int32_ptr_type
|
#define INT32_PTR_TYPE comp_ctx->basic_types.int32_ptr_type
|
||||||
#define INT64_PTR_TYPE comp_ctx->basic_types.int64_ptr_type
|
#define INT64_PTR_TYPE comp_ctx->basic_types.int64_ptr_type
|
||||||
|
|
|
@ -3378,6 +3378,12 @@ aot_resolve_object_data_sections(AOTObjectData *obj_data)
|
||||||
bh_memcpy_s(data_section->name, size, buf, size);
|
bh_memcpy_s(data_section->name, size, buf, size);
|
||||||
data_section->is_name_allocated = true;
|
data_section->is_name_allocated = true;
|
||||||
}
|
}
|
||||||
|
else if (obj_data->comp_ctx->enable_llvm_pgo
|
||||||
|
&& !strcmp(name, "__llvm_prf_bits")) {
|
||||||
|
LOG_WARNING("__llvm_prf_bits section is not supported and "
|
||||||
|
"shouldn't be used in PGO.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (obj_data->comp_ctx->enable_llvm_pgo
|
if (obj_data->comp_ctx->enable_llvm_pgo
|
||||||
&& !strcmp(name, "__llvm_prf_names")) {
|
&& !strcmp(name, "__llvm_prf_names")) {
|
||||||
|
|
|
@ -78,9 +78,6 @@ get_memory_check_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func_ctx->mem_space_unchanged)
|
|
||||||
return mem_check_bound;
|
|
||||||
|
|
||||||
if (!(mem_check_bound = LLVMBuildLoad2(
|
if (!(mem_check_bound = LLVMBuildLoad2(
|
||||||
comp_ctx->builder,
|
comp_ctx->builder,
|
||||||
(comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE : I32_TYPE,
|
(comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE : I32_TYPE,
|
||||||
|
@ -164,17 +161,15 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get memory base address and memory data size */
|
/* Get memory base address and memory data size */
|
||||||
if (func_ctx->mem_space_unchanged
|
|
||||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||||
|| is_shared_memory
|
if (is_shared_memory)
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
mem_base_addr = func_ctx->mem_info[0].mem_base_addr;
|
mem_base_addr = func_ctx->mem_info[0].mem_base_addr;
|
||||||
}
|
else
|
||||||
else {
|
#endif
|
||||||
|
{
|
||||||
if (!(mem_base_addr = LLVMBuildLoad2(
|
if (!(mem_base_addr = LLVMBuildLoad2(
|
||||||
comp_ctx->builder, OPQ_PTR_TYPE,
|
comp_ctx->builder, OPQ_PTR_TYPE,
|
||||||
func_ctx->mem_info[0].mem_base_addr, "mem_base"))) {
|
func_ctx->mem_info[0].mem_base_addr, "mem_base_addr"))) {
|
||||||
aot_set_last_error("llvm build load failed.");
|
aot_set_last_error("llvm build load failed.");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1015,16 +1010,11 @@ get_memory_curr_page_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||||
{
|
{
|
||||||
LLVMValueRef mem_size;
|
LLVMValueRef mem_size;
|
||||||
|
|
||||||
if (func_ctx->mem_space_unchanged) {
|
if (!(mem_size = LLVMBuildLoad2(
|
||||||
mem_size = func_ctx->mem_info[0].mem_cur_page_count_addr;
|
comp_ctx->builder, I32_TYPE,
|
||||||
}
|
func_ctx->mem_info[0].mem_cur_page_count, "mem_size"))) {
|
||||||
else {
|
aot_set_last_error("llvm build load failed.");
|
||||||
if (!(mem_size = LLVMBuildLoad2(
|
goto fail;
|
||||||
comp_ctx->builder, I32_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_cur_page_count_addr, "mem_size"))) {
|
|
||||||
aot_set_last_error("llvm build load failed.");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LLVMBuildIntCast(comp_ctx->builder, mem_size,
|
return LLVMBuildIntCast(comp_ctx->builder, mem_size,
|
||||||
|
@ -1165,16 +1155,14 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||||
bool is_shared_memory = comp_ctx->comp_data->memories[0].flags & 0x02;
|
bool is_shared_memory = comp_ctx->comp_data->memories[0].flags & 0x02;
|
||||||
|
|
||||||
if (func_ctx->mem_space_unchanged || is_shared_memory) {
|
if (is_shared_memory)
|
||||||
#else
|
|
||||||
if (func_ctx->mem_space_unchanged) {
|
|
||||||
#endif
|
|
||||||
mem_base_addr = func_ctx->mem_info[0].mem_base_addr;
|
mem_base_addr = func_ctx->mem_info[0].mem_base_addr;
|
||||||
}
|
else
|
||||||
else {
|
#endif
|
||||||
|
{
|
||||||
if (!(mem_base_addr = LLVMBuildLoad2(
|
if (!(mem_base_addr = LLVMBuildLoad2(
|
||||||
comp_ctx->builder, OPQ_PTR_TYPE,
|
comp_ctx->builder, OPQ_PTR_TYPE,
|
||||||
func_ctx->mem_info[0].mem_base_addr, "mem_base"))) {
|
func_ctx->mem_info[0].mem_base_addr, "mem_base_addr"))) {
|
||||||
aot_set_last_error("llvm build load failed.");
|
aot_set_last_error("llvm build load failed.");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1206,16 +1194,11 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func_ctx->mem_space_unchanged) {
|
if (!(mem_size = LLVMBuildLoad2(
|
||||||
mem_size = func_ctx->mem_info[0].mem_data_size_addr;
|
comp_ctx->builder, I64_TYPE,
|
||||||
}
|
func_ctx->mem_info[0].mem_data_size, "mem_size"))) {
|
||||||
else {
|
aot_set_last_error("llvm build load failed.");
|
||||||
if (!(mem_size = LLVMBuildLoad2(
|
goto fail;
|
||||||
comp_ctx->builder, I64_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_data_size_addr, "mem_size"))) {
|
|
||||||
aot_set_last_error("llvm build load failed.");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
||||||
|
|
|
@ -1186,83 +1186,86 @@ create_local_variables(const AOTCompData *comp_data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
restore_from_addr(const AOTCompContext *comp_ctx, const char *name,
|
||||||
LLVMTypeRef int8_ptr_type, uint32 func_index)
|
LLVMTypeRef type, LLVMValueRef src, LLVMValueRef dest)
|
||||||
{
|
{
|
||||||
LLVMValueRef offset, mem_info_base;
|
LLVMValueRef item;
|
||||||
uint32 memory_count;
|
if (!(item = LLVMBuildLoad2(comp_ctx->builder, type, src, name))) {
|
||||||
WASMModule *module = comp_ctx->comp_data->wasm_module;
|
aot_set_last_error("llvm build load failed");
|
||||||
WASMFunction *func = module->functions[func_index];
|
|
||||||
LLVMTypeRef bound_check_type;
|
|
||||||
bool mem_space_unchanged =
|
|
||||||
(!func->has_op_memory_grow && !func->has_op_func_call)
|
|
||||||
|| (!module->possible_memory_grow);
|
|
||||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
|
||||||
bool is_shared_memory;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
func_ctx->mem_space_unchanged = mem_space_unchanged;
|
|
||||||
|
|
||||||
memory_count = module->memory_count + module->import_memory_count;
|
|
||||||
/* If the module doesn't have memory, reserve
|
|
||||||
one mem_info space with empty content */
|
|
||||||
if (memory_count == 0)
|
|
||||||
memory_count = 1;
|
|
||||||
|
|
||||||
if (!(func_ctx->mem_info =
|
|
||||||
wasm_runtime_malloc(sizeof(AOTMemInfo) * memory_count))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memset(func_ctx->mem_info, 0, sizeof(AOTMemInfo));
|
if (!LLVMBuildStore(comp_ctx->builder, item, dest)) {
|
||||||
|
aot_set_last_error("llvm build store failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Currently we only create memory info for memory 0 */
|
|
||||||
/* Load memory base address */
|
|
||||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||||
is_shared_memory =
|
static LLVMValueRef
|
||||||
comp_ctx->comp_data->memories[0].flags & 0x02 ? true : false;
|
aot_get_shared_mem_addr(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||||
|
{
|
||||||
|
LLVMValueRef offset, shared_mem_addr;
|
||||||
|
offset = I32_CONST(offsetof(AOTModuleInstance, memories));
|
||||||
|
if (!offset) {
|
||||||
|
aot_set_last_error("create llvm const failed.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* aot_inst->memories */
|
||||||
|
if (!(shared_mem_addr = LLVMBuildInBoundsGEP2(
|
||||||
|
comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
|
||||||
|
"shared_mem_addr_offset"))) {
|
||||||
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(shared_mem_addr =
|
||||||
|
LLVMBuildBitCast(comp_ctx->builder, shared_mem_addr,
|
||||||
|
INT8_PPTR_TYPE, "shared_mem_addr_ptr"))) {
|
||||||
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* aot_inst->memories[0] */
|
||||||
|
if (!(shared_mem_addr =
|
||||||
|
LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE,
|
||||||
|
shared_mem_addr, "shared_mem_addr"))) {
|
||||||
|
aot_set_last_error("llvm build load failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(shared_mem_addr =
|
||||||
|
LLVMBuildBitCast(comp_ctx->builder, shared_mem_addr,
|
||||||
|
INT8_PPTR_TYPE, "shared_mem_addr_ptr"))) {
|
||||||
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(shared_mem_addr =
|
||||||
|
LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE,
|
||||||
|
shared_mem_addr, "shared_mem_addr"))) {
|
||||||
|
aot_set_last_error("llvm build load failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return shared_mem_addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool
|
||||||
|
restore_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
||||||
|
{
|
||||||
|
LLVMValueRef offset, mem_info_base, mem_base_addr_addr,
|
||||||
|
mem_cur_page_count_addr, mem_data_size_addr, bound_check_addr;
|
||||||
|
LLVMTypeRef bound_check_type, bound_check_ptr_type;
|
||||||
|
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||||
|
bool is_shared_memory =
|
||||||
|
comp_ctx->comp_data->memories[0].flags & 0x02 ? true : false;
|
||||||
|
|
||||||
if (is_shared_memory) {
|
if (is_shared_memory) {
|
||||||
LLVMValueRef shared_mem_addr;
|
LLVMValueRef shared_mem_addr;
|
||||||
offset = I32_CONST(offsetof(AOTModuleInstance, memories));
|
if (!(shared_mem_addr = aot_get_shared_mem_addr(comp_ctx, func_ctx)))
|
||||||
if (!offset) {
|
|
||||||
aot_set_last_error("create llvm const failed.");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
/* aot_inst->memories */
|
|
||||||
if (!(shared_mem_addr = LLVMBuildInBoundsGEP2(
|
|
||||||
comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
|
|
||||||
"shared_mem_addr_offset"))) {
|
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(shared_mem_addr =
|
|
||||||
LLVMBuildBitCast(comp_ctx->builder, shared_mem_addr,
|
|
||||||
int8_ptr_type, "shared_mem_addr_ptr"))) {
|
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* aot_inst->memories[0] */
|
|
||||||
if (!(shared_mem_addr =
|
|
||||||
LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE,
|
|
||||||
shared_mem_addr, "shared_mem_addr"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(shared_mem_addr =
|
|
||||||
LLVMBuildBitCast(comp_ctx->builder, shared_mem_addr,
|
|
||||||
int8_ptr_type, "shared_mem_addr_ptr"))) {
|
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(shared_mem_addr =
|
|
||||||
LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE,
|
|
||||||
shared_mem_addr, "shared_mem_addr"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* memories[0]->memory_data */
|
/* memories[0]->memory_data */
|
||||||
offset = I32_CONST(offsetof(AOTMemoryInstance, memory_data));
|
offset = I32_CONST(offsetof(AOTMemoryInstance, memory_data));
|
||||||
if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildInBoundsGEP2(
|
if (!(mem_base_addr_addr = LLVMBuildInBoundsGEP2(
|
||||||
comp_ctx->builder, INT8_TYPE, shared_mem_addr, &offset, 1,
|
comp_ctx->builder, INT8_TYPE, shared_mem_addr, &offset, 1,
|
||||||
"mem_base_addr_offset"))) {
|
"mem_base_addr_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
|
@ -1270,16 +1273,15 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
}
|
}
|
||||||
/* memories[0]->cur_page_count */
|
/* memories[0]->cur_page_count */
|
||||||
offset = I32_CONST(offsetof(AOTMemoryInstance, cur_page_count));
|
offset = I32_CONST(offsetof(AOTMemoryInstance, cur_page_count));
|
||||||
if (!(func_ctx->mem_info[0].mem_cur_page_count_addr =
|
if (!(mem_cur_page_count_addr = LLVMBuildInBoundsGEP2(
|
||||||
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
|
comp_ctx->builder, INT8_TYPE, shared_mem_addr, &offset, 1,
|
||||||
shared_mem_addr, &offset, 1,
|
"mem_cur_page_count_offset"))) {
|
||||||
"mem_cur_page_offset"))) {
|
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* memories[0]->memory_data_size */
|
/* memories[0]->memory_data_size */
|
||||||
offset = I32_CONST(offsetof(AOTMemoryInstance, memory_data_size));
|
offset = I32_CONST(offsetof(AOTMemoryInstance, memory_data_size));
|
||||||
if (!(func_ctx->mem_info[0].mem_data_size_addr = LLVMBuildInBoundsGEP2(
|
if (!(mem_data_size_addr = LLVMBuildInBoundsGEP2(
|
||||||
comp_ctx->builder, INT8_TYPE, shared_mem_addr, &offset, 1,
|
comp_ctx->builder, INT8_TYPE, shared_mem_addr, &offset, 1,
|
||||||
"mem_data_size_offset"))) {
|
"mem_data_size_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
|
@ -1300,7 +1302,7 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
|
|
||||||
offset = I32_CONST(offset_of_global_table_data
|
offset = I32_CONST(offset_of_global_table_data
|
||||||
+ offsetof(AOTMemoryInstance, memory_data));
|
+ offsetof(AOTMemoryInstance, memory_data));
|
||||||
if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildInBoundsGEP2(
|
if (!(mem_base_addr_addr = LLVMBuildInBoundsGEP2(
|
||||||
comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
|
comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
|
||||||
"mem_base_addr_offset"))) {
|
"mem_base_addr_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
|
@ -1308,16 +1310,15 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
}
|
}
|
||||||
offset = I32_CONST(offset_of_global_table_data
|
offset = I32_CONST(offset_of_global_table_data
|
||||||
+ offsetof(AOTMemoryInstance, cur_page_count));
|
+ offsetof(AOTMemoryInstance, cur_page_count));
|
||||||
if (!(func_ctx->mem_info[0].mem_cur_page_count_addr =
|
if (!(mem_cur_page_count_addr = LLVMBuildInBoundsGEP2(
|
||||||
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
|
comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
|
||||||
func_ctx->aot_inst, &offset, 1,
|
"mem_cur_page_count_offset"))) {
|
||||||
"mem_cur_page_offset"))) {
|
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
offset = I32_CONST(offset_of_global_table_data
|
offset = I32_CONST(offset_of_global_table_data
|
||||||
+ offsetof(AOTMemoryInstance, memory_data_size));
|
+ offsetof(AOTMemoryInstance, memory_data_size));
|
||||||
if (!(func_ctx->mem_info[0].mem_data_size_addr = LLVMBuildInBoundsGEP2(
|
if (!(mem_data_size_addr = LLVMBuildInBoundsGEP2(
|
||||||
comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
|
comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
|
||||||
"mem_data_size_offset"))) {
|
"mem_data_size_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
|
@ -1325,196 +1326,260 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Store mem info base address before cast */
|
/* Store mem info base address before cast */
|
||||||
mem_info_base = func_ctx->mem_info[0].mem_base_addr;
|
mem_info_base = mem_base_addr_addr;
|
||||||
|
|
||||||
if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildBitCast(
|
|
||||||
comp_ctx->builder, func_ctx->mem_info[0].mem_base_addr,
|
|
||||||
int8_ptr_type, "mem_base_addr_ptr"))) {
|
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(func_ctx->mem_info[0].mem_cur_page_count_addr = LLVMBuildBitCast(
|
|
||||||
comp_ctx->builder, func_ctx->mem_info[0].mem_cur_page_count_addr,
|
|
||||||
INT32_PTR_TYPE, "mem_cur_page_ptr"))) {
|
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(func_ctx->mem_info[0].mem_data_size_addr = LLVMBuildBitCast(
|
|
||||||
comp_ctx->builder, func_ctx->mem_info[0].mem_data_size_addr,
|
|
||||||
INT64_PTR_TYPE, "mem_data_size_ptr"))) {
|
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (mem_space_unchanged) {
|
|
||||||
if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildLoad2(
|
|
||||||
comp_ctx->builder, OPQ_PTR_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_base_addr, "mem_base_addr"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(func_ctx->mem_info[0].mem_cur_page_count_addr =
|
|
||||||
LLVMBuildLoad2(comp_ctx->builder, I32_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_cur_page_count_addr,
|
|
||||||
"mem_cur_page_count"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(func_ctx->mem_info[0].mem_data_size_addr = LLVMBuildLoad2(
|
|
||||||
comp_ctx->builder, I64_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_data_size_addr, "mem_data_size"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||||
else if (is_shared_memory) {
|
if (is_shared_memory) {
|
||||||
/* The base address for shared memory will never changed,
|
/* The base address for shared memory will never changed */
|
||||||
we can load the value here */
|
}
|
||||||
if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildLoad2(
|
else
|
||||||
comp_ctx->builder, OPQ_PTR_TYPE,
|
#endif
|
||||||
func_ctx->mem_info[0].mem_base_addr, "mem_base_addr"))) {
|
{
|
||||||
aot_set_last_error("llvm build load failed");
|
/* Store mem_info[0].mem_base_addr */
|
||||||
|
if (!(mem_base_addr_addr = LLVMBuildBitCast(
|
||||||
|
comp_ctx->builder, mem_base_addr_addr, INT8_PPTR_TYPE,
|
||||||
|
"mem_base_addr_addr"))) {
|
||||||
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!restore_from_addr(
|
||||||
|
comp_ctx, "mem_base_addr", OPQ_PTR_TYPE, mem_base_addr_addr,
|
||||||
|
func_ctx->mem_info[0].mem_base_addr))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bound_check_type = (comp_ctx->pointer_size == sizeof(uint64))
|
/* Store mem_info[0].mem_cur_page_count */
|
||||||
? INT64_PTR_TYPE
|
if (!(mem_cur_page_count_addr = LLVMBuildBitCast(
|
||||||
: INT32_PTR_TYPE;
|
comp_ctx->builder, mem_cur_page_count_addr, INT32_PTR_TYPE,
|
||||||
|
"mem_cur_page_count_addr"))) {
|
||||||
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!restore_from_addr(
|
||||||
|
comp_ctx, "mem_cur_page_count", I32_TYPE, mem_cur_page_count_addr,
|
||||||
|
func_ctx->mem_info[0].mem_cur_page_count))
|
||||||
|
return false;
|
||||||
|
|
||||||
/* Load memory bound check constants */
|
/* Store mem_info[0].mem_data_size */
|
||||||
|
if (!(mem_data_size_addr = LLVMBuildBitCast(
|
||||||
|
comp_ctx->builder, mem_data_size_addr, INT64_PTR_TYPE,
|
||||||
|
"mem_data_size_addr"))) {
|
||||||
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!restore_from_addr(
|
||||||
|
comp_ctx, "mem_data_size", I64_TYPE, mem_data_size_addr,
|
||||||
|
func_ctx->mem_info[0].mem_data_size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Store memory bound check constants */
|
||||||
|
bound_check_type = (comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE
|
||||||
|
: I32_TYPE;
|
||||||
|
bound_check_ptr_type = (comp_ctx->pointer_size == sizeof(uint64))
|
||||||
|
? INT64_PTR_TYPE
|
||||||
|
: INT32_PTR_TYPE;
|
||||||
|
|
||||||
|
/* Store mem_info[0].mem_bound_check_1byte */
|
||||||
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_1byte)
|
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_1byte)
|
||||||
- offsetof(AOTMemoryInstance, memory_data));
|
- offsetof(AOTMemoryInstance, memory_data));
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_1byte =
|
if (!(bound_check_addr = LLVMBuildInBoundsGEP2(
|
||||||
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, mem_info_base,
|
comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1,
|
||||||
&offset, 1, "bound_check_1byte_offset"))) {
|
"bound_check_1byte_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_1byte = LLVMBuildBitCast(
|
if (!(bound_check_addr = LLVMBuildBitCast(
|
||||||
comp_ctx->builder, func_ctx->mem_info[0].mem_bound_check_1byte,
|
comp_ctx->builder, bound_check_addr, bound_check_ptr_type,
|
||||||
bound_check_type, "bound_check_1byte_ptr"))) {
|
"bound_check_1byte_addr"))) {
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mem_space_unchanged) {
|
if (!restore_from_addr(
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_1byte = LLVMBuildLoad2(
|
comp_ctx, "mem_bound_check_1byte", bound_check_type,
|
||||||
comp_ctx->builder,
|
bound_check_addr, func_ctx->mem_info[0].mem_bound_check_1byte))
|
||||||
(comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE
|
return false;
|
||||||
: I32_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_bound_check_1byte,
|
|
||||||
"bound_check_1byte"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Store mem_info[0].mem_bound_check_2bytes */
|
||||||
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_2bytes)
|
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_2bytes)
|
||||||
- offsetof(AOTMemoryInstance, memory_data));
|
- offsetof(AOTMemoryInstance, memory_data));
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_2bytes =
|
if (!(bound_check_addr = LLVMBuildInBoundsGEP2(
|
||||||
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, mem_info_base,
|
comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1,
|
||||||
&offset, 1, "bound_check_2bytes_offset"))) {
|
"bound_check_2bytes_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_2bytes = LLVMBuildBitCast(
|
if (!(bound_check_addr = LLVMBuildBitCast(
|
||||||
comp_ctx->builder, func_ctx->mem_info[0].mem_bound_check_2bytes,
|
comp_ctx->builder, bound_check_addr, bound_check_ptr_type,
|
||||||
bound_check_type, "bound_check_2bytes_ptr"))) {
|
"bound_check_2bytes_addr"))) {
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mem_space_unchanged) {
|
if (!restore_from_addr(
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_2bytes = LLVMBuildLoad2(
|
comp_ctx, "mem_bound_check_2bytes", bound_check_type,
|
||||||
comp_ctx->builder,
|
bound_check_addr, func_ctx->mem_info[0].mem_bound_check_2bytes))
|
||||||
(comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE
|
return false;
|
||||||
: I32_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_bound_check_2bytes,
|
|
||||||
"bound_check_2bytes"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Store mem_info[0].mem_bound_check_4bytes */
|
||||||
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_4bytes)
|
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_4bytes)
|
||||||
- offsetof(AOTMemoryInstance, memory_data));
|
- offsetof(AOTMemoryInstance, memory_data));
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_4bytes =
|
if (!(bound_check_addr = LLVMBuildInBoundsGEP2(
|
||||||
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, mem_info_base,
|
comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1,
|
||||||
&offset, 1, "bound_check_4bytes_offset"))) {
|
"bound_check_4bytes_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_4bytes = LLVMBuildBitCast(
|
if (!(bound_check_addr = LLVMBuildBitCast(
|
||||||
comp_ctx->builder, func_ctx->mem_info[0].mem_bound_check_4bytes,
|
comp_ctx->builder, bound_check_addr, bound_check_ptr_type,
|
||||||
bound_check_type, "bound_check_4bytes_ptr"))) {
|
"bound_check_4bytes_addr"))) {
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mem_space_unchanged) {
|
if (!restore_from_addr(
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_4bytes = LLVMBuildLoad2(
|
comp_ctx, "mem_bound_check_4bytes", bound_check_type,
|
||||||
comp_ctx->builder,
|
bound_check_addr, func_ctx->mem_info[0].mem_bound_check_4bytes))
|
||||||
(comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE
|
return false;
|
||||||
: I32_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_bound_check_4bytes,
|
|
||||||
"bound_check_4bytes"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Store mem_info[0].mem_bound_check_8bytes */
|
||||||
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_8bytes)
|
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_8bytes)
|
||||||
- offsetof(AOTMemoryInstance, memory_data));
|
- offsetof(AOTMemoryInstance, memory_data));
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_8bytes =
|
if (!(bound_check_addr = LLVMBuildInBoundsGEP2(
|
||||||
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, mem_info_base,
|
comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1,
|
||||||
&offset, 1, "bound_check_8bytes_offset"))) {
|
"bound_check_8bytes_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_8bytes = LLVMBuildBitCast(
|
if (!(bound_check_addr = LLVMBuildBitCast(
|
||||||
comp_ctx->builder, func_ctx->mem_info[0].mem_bound_check_8bytes,
|
comp_ctx->builder, bound_check_addr, bound_check_ptr_type,
|
||||||
bound_check_type, "bound_check_8bytes_ptr"))) {
|
"bound_check_8bytes_addr"))) {
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mem_space_unchanged) {
|
if (!restore_from_addr(
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_8bytes = LLVMBuildLoad2(
|
comp_ctx, "mem_bound_check_8bytes", bound_check_type,
|
||||||
comp_ctx->builder,
|
bound_check_addr, func_ctx->mem_info[0].mem_bound_check_8bytes))
|
||||||
(comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE
|
return false;
|
||||||
: I32_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_bound_check_8bytes,
|
|
||||||
"bound_check_8bytes"))) {
|
|
||||||
aot_set_last_error("llvm build load failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Store mem_info[0].mem_bound_check_16bytes */
|
||||||
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_16bytes)
|
offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_16bytes)
|
||||||
- offsetof(AOTMemoryInstance, memory_data));
|
- offsetof(AOTMemoryInstance, memory_data));
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_16bytes = LLVMBuildInBoundsGEP2(
|
if (!(bound_check_addr = LLVMBuildInBoundsGEP2(
|
||||||
comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1,
|
comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1,
|
||||||
"bound_check_16bytes_offset"))) {
|
"bound_check_16bytes_offset"))) {
|
||||||
aot_set_last_error("llvm build in bounds gep failed");
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_16bytes = LLVMBuildBitCast(
|
if (!(bound_check_addr = LLVMBuildBitCast(
|
||||||
comp_ctx->builder, func_ctx->mem_info[0].mem_bound_check_16bytes,
|
comp_ctx->builder, bound_check_addr, bound_check_ptr_type,
|
||||||
bound_check_type, "bound_check_16bytes_ptr"))) {
|
"bound_check_16bytes_addr"))) {
|
||||||
aot_set_last_error("llvm build bit cast failed");
|
aot_set_last_error("llvm build bit cast failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mem_space_unchanged) {
|
if (!restore_from_addr(
|
||||||
if (!(func_ctx->mem_info[0].mem_bound_check_16bytes = LLVMBuildLoad2(
|
comp_ctx, "mem_bound_check_16bytes", bound_check_type,
|
||||||
comp_ctx->builder,
|
bound_check_addr, func_ctx->mem_info[0].mem_bound_check_16bytes))
|
||||||
(comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE
|
return false;
|
||||||
: I32_TYPE,
|
|
||||||
func_ctx->mem_info[0].mem_bound_check_16bytes,
|
return true;
|
||||||
"bound_check_16bytes"))) {
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||||
|
uint32 func_index)
|
||||||
|
{
|
||||||
|
LLVMValueRef offset;
|
||||||
|
uint32 memory_count;
|
||||||
|
WASMModule *module = comp_ctx->comp_data->wasm_module;
|
||||||
|
LLVMTypeRef bound_check_type;
|
||||||
|
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||||
|
bool is_shared_memory;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memory_count = module->memory_count + module->import_memory_count;
|
||||||
|
/* If the module doesn't have memory, reserve
|
||||||
|
one mem_info space with empty content */
|
||||||
|
if (memory_count == 0)
|
||||||
|
memory_count = 1;
|
||||||
|
|
||||||
|
if (!(func_ctx->mem_info =
|
||||||
|
wasm_runtime_malloc(sizeof(AOTMemInfo) * memory_count))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(func_ctx->mem_info, 0, sizeof(AOTMemInfo));
|
||||||
|
|
||||||
|
/* Currently we only create memory info for memory 0 */
|
||||||
|
/* Load memory base address */
|
||||||
|
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||||
|
is_shared_memory =
|
||||||
|
comp_ctx->comp_data->memories[0].flags & 0x02 ? true : false;
|
||||||
|
if (is_shared_memory) {
|
||||||
|
LLVMValueRef shared_mem_addr, mem_base_addr_addr;
|
||||||
|
if (!(shared_mem_addr = aot_get_shared_mem_addr(comp_ctx, func_ctx)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* memories[0]->memory_data */
|
||||||
|
offset = I32_CONST(offsetof(AOTMemoryInstance, memory_data));
|
||||||
|
if (!(mem_base_addr_addr = LLVMBuildInBoundsGEP2(
|
||||||
|
comp_ctx->builder, INT8_TYPE, shared_mem_addr, &offset, 1,
|
||||||
|
"mem_base_addr_offset"))) {
|
||||||
|
aot_set_last_error("llvm build in bounds gep failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* The base address for shared memory will never changed,
|
||||||
|
we can load the value here */
|
||||||
|
if (!(func_ctx->mem_info[0].mem_base_addr =
|
||||||
|
LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE,
|
||||||
|
mem_base_addr_addr, "mem_base_addr"))) {
|
||||||
aot_set_last_error("llvm build load failed");
|
aot_set_last_error("llvm build load failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildAlloca(
|
||||||
|
comp_ctx->builder, OPQ_PTR_TYPE, "mem_base_addr"))) {
|
||||||
|
aot_set_last_error("llvm build alloca failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(func_ctx->mem_info[0].mem_data_size = LLVMBuildAlloca(
|
||||||
|
comp_ctx->builder, I64_TYPE, "mem_data_size"))) {
|
||||||
|
aot_set_last_error("llvm build alloca failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(func_ctx->mem_info[0].mem_cur_page_count = LLVMBuildAlloca(
|
||||||
|
comp_ctx->builder, I32_TYPE, "mem_cur_page_count"))) {
|
||||||
|
aot_set_last_error("llvm build alloca failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bound_check_type = (comp_ctx->pointer_size == sizeof(uint64)) ? I64_TYPE
|
||||||
|
: I32_TYPE;
|
||||||
|
if (!(func_ctx->mem_info[0].mem_bound_check_1byte = LLVMBuildAlloca(
|
||||||
|
comp_ctx->builder, bound_check_type, "mem_bound_check_1byte"))) {
|
||||||
|
aot_set_last_error("llvm build alloca failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(func_ctx->mem_info[0].mem_bound_check_2bytes = LLVMBuildAlloca(
|
||||||
|
comp_ctx->builder, bound_check_type, "mem_bound_check_2bytes"))) {
|
||||||
|
aot_set_last_error("llvm build alloca failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(func_ctx->mem_info[0].mem_bound_check_4bytes = LLVMBuildAlloca(
|
||||||
|
comp_ctx->builder, bound_check_type, "mem_bound_check_4bytes"))) {
|
||||||
|
aot_set_last_error("llvm build alloca failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(func_ctx->mem_info[0].mem_bound_check_8bytes = LLVMBuildAlloca(
|
||||||
|
comp_ctx->builder, bound_check_type, "mem_bound_check_8bytes"))) {
|
||||||
|
aot_set_last_error("llvm build alloca failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(func_ctx->mem_info[0].mem_bound_check_16bytes = LLVMBuildAlloca(
|
||||||
|
comp_ctx->builder, bound_check_type, "mem_bound_check_16bytes"))) {
|
||||||
|
aot_set_last_error("llvm build alloca failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return restore_memory_info(comp_ctx, func_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -1785,7 +1850,6 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
|
||||||
WASMModule *module = comp_ctx->comp_data->wasm_module;
|
WASMModule *module = comp_ctx->comp_data->wasm_module;
|
||||||
WASMFunction *wasm_func = module->functions[func_index];
|
WASMFunction *wasm_func = module->functions[func_index];
|
||||||
AOTBlock *aot_block;
|
AOTBlock *aot_block;
|
||||||
LLVMTypeRef int8_ptr_type;
|
|
||||||
uint64 size;
|
uint64 size;
|
||||||
|
|
||||||
/* Allocate memory for the function context */
|
/* Allocate memory for the function context */
|
||||||
|
@ -1849,14 +1913,9 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(int8_ptr_type = LLVMPointerType(INT8_PTR_TYPE, 0))) {
|
|
||||||
aot_set_last_error("llvm add pointer type failed.");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create base addr, end addr, data size of mem, heap */
|
/* Create base addr, end addr, data size of mem, heap */
|
||||||
if (wasm_func->has_memory_operations
|
if (wasm_func->has_memory_operations
|
||||||
&& !create_memory_info(comp_ctx, func_ctx, int8_ptr_type, func_index)) {
|
&& !create_memory_info(comp_ctx, func_ctx, func_index)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3204,6 +3263,21 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
|
||||||
|
|
||||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||||
WASMModule *wasm_module = (WASMModule *)comp_data->wasm_module;
|
WASMModule *wasm_module = (WASMModule *)comp_data->wasm_module;
|
||||||
|
bool is_memory64 = false;
|
||||||
|
|
||||||
|
/* TODO: multi-memories for now assuming the memory64 flag of a memory is
|
||||||
|
* consistent across multi-memories */
|
||||||
|
if (wasm_module->import_memory_count > 0)
|
||||||
|
is_memory64 = !!(wasm_module->import_memories[0].u.memory.mem_type.flags
|
||||||
|
& MEMORY64_FLAG);
|
||||||
|
else if (wasm_module->memory_count > 0)
|
||||||
|
is_memory64 = !!(wasm_module->memories[0].flags & MEMORY64_FLAG);
|
||||||
|
|
||||||
|
if (!(option->bounds_checks == 1 || option->bounds_checks == 0)
|
||||||
|
&& is_memory64) {
|
||||||
|
/* For memory64, the boundary check default value is true */
|
||||||
|
comp_ctx->enable_bound_check = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return error if SIMD is disabled by command line but SIMD instructions
|
/* Return error if SIMD is disabled by command line but SIMD instructions
|
||||||
* are used */
|
* are used */
|
||||||
|
|
|
@ -215,8 +215,8 @@ typedef struct AOTCheckedAddr {
|
||||||
|
|
||||||
typedef struct AOTMemInfo {
|
typedef struct AOTMemInfo {
|
||||||
LLVMValueRef mem_base_addr;
|
LLVMValueRef mem_base_addr;
|
||||||
LLVMValueRef mem_data_size_addr;
|
LLVMValueRef mem_data_size;
|
||||||
LLVMValueRef mem_cur_page_count_addr;
|
LLVMValueRef mem_cur_page_count;
|
||||||
LLVMValueRef mem_bound_check_1byte;
|
LLVMValueRef mem_bound_check_1byte;
|
||||||
LLVMValueRef mem_bound_check_2bytes;
|
LLVMValueRef mem_bound_check_2bytes;
|
||||||
LLVMValueRef mem_bound_check_4bytes;
|
LLVMValueRef mem_bound_check_4bytes;
|
||||||
|
@ -251,7 +251,6 @@ typedef struct AOTFuncContext {
|
||||||
LLVMValueRef wasm_stack_top_bound;
|
LLVMValueRef wasm_stack_top_bound;
|
||||||
LLVMValueRef wasm_stack_top_ptr;
|
LLVMValueRef wasm_stack_top_ptr;
|
||||||
|
|
||||||
bool mem_space_unchanged;
|
|
||||||
AOTCheckedAddrList checked_addr_list;
|
AOTCheckedAddrList checked_addr_list;
|
||||||
|
|
||||||
LLVMValueRef shared_heap_base_addr_adj;
|
LLVMValueRef shared_heap_base_addr_adj;
|
||||||
|
@ -656,6 +655,9 @@ unsigned int
|
||||||
aot_estimate_stack_usage_for_function_call(const AOTCompContext *comp_ctx,
|
aot_estimate_stack_usage_for_function_call(const AOTCompContext *comp_ctx,
|
||||||
const AOTFuncType *callee_func_type);
|
const AOTFuncType *callee_func_type);
|
||||||
|
|
||||||
|
bool
|
||||||
|
restore_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* end of extern "C" */
|
} /* end of extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -139,8 +139,6 @@ typedef struct wasm_frame_t {
|
||||||
uint32_t *lp;
|
uint32_t *lp;
|
||||||
} WASMCApiFrame;
|
} WASMCApiFrame;
|
||||||
|
|
||||||
typedef WASMCApiFrame wasm_frame_t;
|
|
||||||
|
|
||||||
/* WASM section */
|
/* WASM section */
|
||||||
typedef struct wasm_section_t {
|
typedef struct wasm_section_t {
|
||||||
struct wasm_section_t *next;
|
struct wasm_section_t *next;
|
||||||
|
@ -904,7 +902,7 @@ wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env);
|
||||||
* @return number of copied frames
|
* @return number of copied frames
|
||||||
*/
|
*/
|
||||||
WASM_RUNTIME_API_EXTERN uint32_t
|
WASM_RUNTIME_API_EXTERN uint32_t
|
||||||
wasm_copy_callstack(const wasm_exec_env_t exec_env, wasm_frame_t *buffer,
|
wasm_copy_callstack(const wasm_exec_env_t exec_env, WASMCApiFrame *buffer,
|
||||||
const uint32_t length, const uint32_t skip_n,
|
const uint32_t length, const uint32_t skip_n,
|
||||||
char *error_buf, uint32_t error_buf_size);
|
char *error_buf, uint32_t error_buf_size);
|
||||||
|
|
||||||
|
|
|
@ -831,19 +831,24 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
|
||||||
{
|
{
|
||||||
uint8 type1;
|
uint8 type1;
|
||||||
|
|
||||||
|
#if WASM_ENABLE_GC == 0
|
||||||
CHECK_BUF(p, p_end, 1);
|
CHECK_BUF(p, p_end, 1);
|
||||||
type1 = read_uint8(p);
|
type1 = read_uint8(p);
|
||||||
|
|
||||||
#if WASM_ENABLE_GC == 0
|
|
||||||
cur_value.ref_index = NULL_REF;
|
cur_value.ref_index = NULL_REF;
|
||||||
if (!push_const_expr_stack(&const_expr_ctx, flag, type1,
|
if (!push_const_expr_stack(&const_expr_ctx, flag, type1,
|
||||||
&cur_value, error_buf,
|
&cur_value, error_buf,
|
||||||
error_buf_size))
|
error_buf_size))
|
||||||
goto fail;
|
goto fail;
|
||||||
#else
|
#else
|
||||||
|
int32 heap_type;
|
||||||
|
read_leb_int32(p, p_end, heap_type);
|
||||||
|
type1 = (uint8)((int32)0x80 + heap_type);
|
||||||
|
|
||||||
cur_value.gc_obj = NULL_REF;
|
cur_value.gc_obj = NULL_REF;
|
||||||
|
|
||||||
if (!is_byte_a_type(type1)
|
if (!is_byte_a_type(type1)
|
||||||
|
|| !wasm_is_valid_heap_type(heap_type)
|
||||||
|| wasm_is_type_multi_byte_type(type1)) {
|
|| wasm_is_type_multi_byte_type(type1)) {
|
||||||
p--;
|
p--;
|
||||||
read_leb_uint32(p, p_end, type_idx);
|
read_leb_uint32(p, p_end, type_idx);
|
||||||
|
@ -2583,7 +2588,8 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
|
||||||
error_buf_size)) {
|
error_buf_size)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (wasm_is_reftype_htref_non_nullable(ref_type.ref_type)) {
|
if (!wasm_is_type_reftype(ref_type.ref_type)
|
||||||
|
|| wasm_is_reftype_htref_non_nullable(ref_type.ref_type)) {
|
||||||
set_error_buf(error_buf, error_buf_size, "type mismatch");
|
set_error_buf(error_buf, error_buf_size, "type mismatch");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3109,6 +3115,15 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
|
||||||
error_buf_size)) {
|
error_buf_size)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* TODO: add this validator
|
||||||
|
* `wasm_is_reftype_htref_non_nullable(ref_type.ref_type)`
|
||||||
|
* after sync up with the latest GC spec
|
||||||
|
*/
|
||||||
|
if (!wasm_is_type_reftype(ref_type.ref_type)) {
|
||||||
|
set_error_buf(error_buf, error_buf_size, "type mismatch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
table->table_type.elem_type = ref_type.ref_type;
|
table->table_type.elem_type = ref_type.ref_type;
|
||||||
if (need_ref_type_map) {
|
if (need_ref_type_map) {
|
||||||
if (!(table->table_type.elem_ref_type =
|
if (!(table->table_type.elem_ref_type =
|
||||||
|
@ -3282,6 +3297,13 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||||
CHECK_BUF(p, p_end, 1);
|
CHECK_BUF(p, p_end, 1);
|
||||||
/* 0x70 */
|
/* 0x70 */
|
||||||
u8 = read_uint8(p);
|
u8 = read_uint8(p);
|
||||||
|
#if WASM_ENABLE_GC != 0
|
||||||
|
if (wasm_is_reftype_htref_nullable(u8)) {
|
||||||
|
int32 heap_type;
|
||||||
|
read_leb_int32(p, p_end, heap_type);
|
||||||
|
(void)heap_type;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
read_leb_uint32(p, p_end, flags);
|
read_leb_uint32(p, p_end, flags);
|
||||||
read_leb_uint32(p, p_end, u32);
|
read_leb_uint32(p, p_end, u32);
|
||||||
if (flags & 1)
|
if (flags & 1)
|
||||||
|
@ -3329,7 +3351,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
||||||
/* valtype */
|
/* valtype */
|
||||||
CHECK_BUF(p, p_end, 1);
|
CHECK_BUF(p, p_end, 1);
|
||||||
global_type = read_uint8(p);
|
global_type = read_uint8(p);
|
||||||
if (wasm_is_type_multi_byte_type(global_type)) {
|
if (wasm_is_reftype_htref_nullable(global_type)) {
|
||||||
int32 heap_type;
|
int32 heap_type;
|
||||||
read_leb_int32(p, p_end, heap_type);
|
read_leb_int32(p, p_end, heap_type);
|
||||||
(void)heap_type;
|
(void)heap_type;
|
||||||
|
@ -3690,7 +3712,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
||||||
* we shall make a copy of code body [p_code, p_code + code_size]
|
* we shall make a copy of code body [p_code, p_code + code_size]
|
||||||
* when we are worrying about inappropriate releasing behaviour.
|
* when we are worrying about inappropriate releasing behaviour.
|
||||||
* all code bodies are actually in a buffer which user allocates in
|
* all code bodies are actually in a buffer which user allocates in
|
||||||
* his embedding environment and we don't have power on them.
|
* their embedding environment and we don't have power over them.
|
||||||
* it will be like:
|
* it will be like:
|
||||||
* code_body_cp = malloc(code_size);
|
* code_body_cp = malloc(code_size);
|
||||||
* memcpy(code_body_cp, p_code, code_size);
|
* memcpy(code_body_cp, p_code, code_size);
|
||||||
|
|
|
@ -1226,7 +1226,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
||||||
* we shall make a copy of code body [p_code, p_code + code_size]
|
* we shall make a copy of code body [p_code, p_code + code_size]
|
||||||
* when we are worrying about inappropriate releasing behaviour.
|
* when we are worrying about inappropriate releasing behaviour.
|
||||||
* all code bodies are actually in a buffer which user allocates in
|
* all code bodies are actually in a buffer which user allocates in
|
||||||
* his embedding environment and we don't have power on them.
|
* their embedding environment and we don't have power over them.
|
||||||
* it will be like:
|
* it will be like:
|
||||||
* code_body_cp = malloc(code_size);
|
* code_body_cp = malloc(code_size);
|
||||||
* memcpy(code_body_cp, p_code, code_size);
|
* memcpy(code_body_cp, p_code, code_size);
|
||||||
|
|
|
@ -4195,9 +4195,9 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst,
|
||||||
#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \
|
#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \
|
||||||
|| (WASM_ENABLE_MEMORY_TRACING != 0) */
|
|| (WASM_ENABLE_MEMORY_TRACING != 0) */
|
||||||
|
|
||||||
#if WAMR_ENABLE_COPY_CALLSTACK != 0
|
#if WASM_ENABLE_COPY_CALL_STACK != 0
|
||||||
uint32
|
uint32
|
||||||
wasm_interp_copy_callstack(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
wasm_interp_copy_callstack(WASMExecEnv *exec_env, WASMCApiFrame *buffer,
|
||||||
uint32 length, uint32 skip_n, char *error_buf,
|
uint32 length, uint32 skip_n, char *error_buf,
|
||||||
uint32_t error_buf_size)
|
uint32_t error_buf_size)
|
||||||
{
|
{
|
||||||
|
@ -4242,7 +4242,7 @@ wasm_interp_copy_callstack(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
||||||
}
|
}
|
||||||
return count >= skip_n ? count - skip_n : 0;
|
return count >= skip_n ? count - skip_n : 0;
|
||||||
}
|
}
|
||||||
#endif // WAMR_ENABLE_COPY_CALLSTACK
|
#endif // WASM_ENABLE_COPY_CALL_STACK
|
||||||
|
|
||||||
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -731,12 +731,12 @@ wasm_get_table_inst(const WASMModuleInstance *module_inst, uint32 tbl_idx)
|
||||||
|
|
||||||
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
||||||
|
|
||||||
#if WAMR_ENABLE_COPY_CALLSTACK != 0
|
#if WASM_ENABLE_COPY_CALL_STACK != 0
|
||||||
uint32
|
uint32
|
||||||
wasm_interp_copy_callstack(WASMExecEnv *exec_env, wasm_frame_t *buffer,
|
wasm_interp_copy_callstack(WASMExecEnv *exec_env, WASMCApiFrame *buffer,
|
||||||
uint32 length, uint32 skip_n, char *error_buf,
|
uint32 length, uint32 skip_n, char *error_buf,
|
||||||
uint32_t error_buf_size);
|
uint32_t error_buf_size);
|
||||||
#endif // WAMR_ENABLE_COPY_CALLSTACK
|
#endif // WASM_ENABLE_COPY_CALL_STACK
|
||||||
|
|
||||||
bool
|
bool
|
||||||
wasm_interp_create_call_stack(struct WASMExecEnv *exec_env);
|
wasm_interp_create_call_stack(struct WASMExecEnv *exec_env);
|
||||||
|
|
|
@ -743,7 +743,7 @@ wasm_debug_instance_get_obj_mem(WASMDebugInstance *instance, uint64 offset,
|
||||||
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
||||||
|
|
||||||
if (offset + *size > module_inst->module->load_size) {
|
if (offset + *size > module_inst->module->load_size) {
|
||||||
LOG_VERBOSE("wasm_debug_instance_get_data_mem size over flow!\n");
|
LOG_VERBOSE("wasm_debug_instance_get_data_mem size overflow!\n");
|
||||||
*size = module_inst->module->load_size >= offset
|
*size = module_inst->module->load_size >= offset
|
||||||
? module_inst->module->load_size - offset
|
? module_inst->module->load_size - offset
|
||||||
: 0;
|
: 0;
|
||||||
|
@ -797,7 +797,7 @@ wasm_debug_instance_get_linear_mem(WASMDebugInstance *instance, uint64 offset,
|
||||||
num_bytes_per_page = memory->num_bytes_per_page;
|
num_bytes_per_page = memory->num_bytes_per_page;
|
||||||
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
||||||
if (offset + *size > linear_mem_size) {
|
if (offset + *size > linear_mem_size) {
|
||||||
LOG_VERBOSE("wasm_debug_instance_get_linear_mem size over flow!\n");
|
LOG_VERBOSE("wasm_debug_instance_get_linear_mem size overflow!\n");
|
||||||
*size = linear_mem_size >= offset ? linear_mem_size - offset : 0;
|
*size = linear_mem_size >= offset ? linear_mem_size - offset : 0;
|
||||||
}
|
}
|
||||||
bh_memcpy_s(buf, (uint32)*size, memory->memory_data + offset,
|
bh_memcpy_s(buf, (uint32)*size, memory->memory_data + offset,
|
||||||
|
@ -830,7 +830,7 @@ wasm_debug_instance_set_linear_mem(WASMDebugInstance *instance, uint64 offset,
|
||||||
num_bytes_per_page = memory->num_bytes_per_page;
|
num_bytes_per_page = memory->num_bytes_per_page;
|
||||||
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
||||||
if (offset + *size > linear_mem_size) {
|
if (offset + *size > linear_mem_size) {
|
||||||
LOG_VERBOSE("wasm_debug_instance_get_linear_mem size over flow!\n");
|
LOG_VERBOSE("wasm_debug_instance_get_linear_mem size overflow!\n");
|
||||||
*size = linear_mem_size >= offset ? linear_mem_size - offset : 0;
|
*size = linear_mem_size >= offset ? linear_mem_size - offset : 0;
|
||||||
}
|
}
|
||||||
bh_memcpy_s(memory->memory_data + offset, (uint32)*size, buf,
|
bh_memcpy_s(memory->memory_data + offset, (uint32)*size, buf,
|
||||||
|
|
|
@ -175,6 +175,19 @@ process_wasm_global(WASMGDBServer *server, char *args)
|
||||||
os_mutex_unlock(&tmpbuf_lock);
|
os_mutex_unlock(&tmpbuf_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: let server send an empty/error reply.
|
||||||
|
Original issue: 4265
|
||||||
|
Not tested yet, but it should work.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
send_reply(WASMGDBServer *server, const char *err)
|
||||||
|
{
|
||||||
|
if (!err || !*err)
|
||||||
|
write_packet(server, "");
|
||||||
|
else
|
||||||
|
write_packet(server, err);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
handle_general_query(WASMGDBServer *server, char *payload)
|
handle_general_query(WASMGDBServer *server, char *payload)
|
||||||
{
|
{
|
||||||
|
@ -214,6 +227,7 @@ handle_general_query(WASMGDBServer *server, char *payload)
|
||||||
|
|
||||||
if (!args) {
|
if (!args) {
|
||||||
LOG_ERROR("payload parse error during handle_general_query");
|
LOG_ERROR("payload parse error during handle_general_query");
|
||||||
|
send_reply(server, "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +398,7 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
os_mutex_lock(&tmpbuf_lock);
|
os_mutex_lock(&tmpbuf_lock);
|
||||||
(void)snprintf(tmpbuf, MAX_PACKET_SIZE, "W%02" PRIx32, status);
|
(void)snprintf(tmpbuf, MAX_PACKET_SIZE, "W%02" PRIx32, status);
|
||||||
write_packet(server, tmpbuf);
|
send_reply(server, tmpbuf);
|
||||||
os_mutex_unlock(&tmpbuf_lock);
|
os_mutex_unlock(&tmpbuf_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -403,6 +417,7 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
|
||||||
"T%02" PRIx32 "thread:%" PRIx64 ";name:%s;", gdb_status,
|
"T%02" PRIx32 "thread:%" PRIx64 ";name:%s;", gdb_status,
|
||||||
(uint64)(uintptr_t)tid, "nobody");
|
(uint64)(uintptr_t)tid, "nobody");
|
||||||
if (len < 0 || len >= MAX_PACKET_SIZE) {
|
if (len < 0 || len >= MAX_PACKET_SIZE) {
|
||||||
|
send_reply(server, "E01");
|
||||||
os_mutex_unlock(&tmpbuf_lock);
|
os_mutex_unlock(&tmpbuf_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -410,6 +425,7 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
|
||||||
if (tids_count > 0) {
|
if (tids_count > 0) {
|
||||||
int n = snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, "threads:");
|
int n = snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, "threads:");
|
||||||
if (n < 0 || n >= MAX_PACKET_SIZE - len) {
|
if (n < 0 || n >= MAX_PACKET_SIZE - len) {
|
||||||
|
send_reply(server, "E01");
|
||||||
os_mutex_unlock(&tmpbuf_lock);
|
os_mutex_unlock(&tmpbuf_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -426,6 +442,7 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n < 0 || n >= MAX_PACKET_SIZE - len) {
|
if (n < 0 || n >= MAX_PACKET_SIZE - len) {
|
||||||
|
send_reply(server, "E01");
|
||||||
os_mutex_unlock(&tmpbuf_lock);
|
os_mutex_unlock(&tmpbuf_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -452,6 +469,7 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
|
||||||
"thread-pcs:%" PRIx64 ";00:%s;reason:%s;description:", pc,
|
"thread-pcs:%" PRIx64 ";00:%s;reason:%s;description:", pc,
|
||||||
pc_string, "exception");
|
pc_string, "exception");
|
||||||
if (n < 0 || n >= MAX_PACKET_SIZE - len) {
|
if (n < 0 || n >= MAX_PACKET_SIZE - len) {
|
||||||
|
send_reply(server, "E01");
|
||||||
os_mutex_unlock(&tmpbuf_lock);
|
os_mutex_unlock(&tmpbuf_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -462,6 +480,7 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
|
||||||
n = snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, "%02x",
|
n = snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, "%02x",
|
||||||
exception[i]);
|
exception[i]);
|
||||||
if (n < 0 || n >= MAX_PACKET_SIZE - len) {
|
if (n < 0 || n >= MAX_PACKET_SIZE - len) {
|
||||||
|
send_reply(server, "E01");
|
||||||
os_mutex_unlock(&tmpbuf_lock);
|
os_mutex_unlock(&tmpbuf_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -592,7 +611,7 @@ handle_get_register(WASMGDBServer *server, char *payload)
|
||||||
int32 i = strtol(payload, NULL, 16);
|
int32 i = strtol(payload, NULL, 16);
|
||||||
|
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
write_packet(server, "E01");
|
send_reply(server, "E01");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
regdata = wasm_debug_instance_get_pc(
|
regdata = wasm_debug_instance_get_pc(
|
||||||
|
@ -748,7 +767,7 @@ handle_add_break(WASMGDBServer *server, char *payload)
|
||||||
if ((arg_c = sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length))
|
if ((arg_c = sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length))
|
||||||
!= 3) {
|
!= 3) {
|
||||||
LOG_ERROR("Unsupported number of add break arguments %d", arg_c);
|
LOG_ERROR("Unsupported number of add break arguments %d", arg_c);
|
||||||
write_packet(server, "");
|
send_reply(server, "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,7 +802,7 @@ handle_remove_break(WASMGDBServer *server, char *payload)
|
||||||
if ((arg_c = sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length))
|
if ((arg_c = sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length))
|
||||||
!= 3) {
|
!= 3) {
|
||||||
LOG_ERROR("Unsupported number of remove break arguments %d", arg_c);
|
LOG_ERROR("Unsupported number of remove break arguments %d", arg_c);
|
||||||
write_packet(server, "");
|
send_reply(server, "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,6 +854,7 @@ handle_malloc(WASMGDBServer *server, char *payload)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG_ERROR("Payload parse error during handle malloc");
|
LOG_ERROR("Payload parse error during handle malloc");
|
||||||
|
send_reply(server, "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,26 @@
|
||||||
#include <wasi/api.h>
|
#include <wasi/api.h>
|
||||||
#include <wasi_socket_ext.h>
|
#include <wasi_socket_ext.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid direct TLS access to allow a single library to be
|
||||||
|
* linked to both of threaded and non-threaded applications.
|
||||||
|
*
|
||||||
|
* wasi-libc's errno is a TLS variable, exposed directly via
|
||||||
|
* errno.h. if we use it here, LLVM may lower it differently,
|
||||||
|
* depending on enabled features like atomcs and bulk-memory.
|
||||||
|
* we tweak the way to access errno here in order to make us
|
||||||
|
* compatible with both of threaded and non-threaded applications.
|
||||||
|
* __errno_location() should be reasonably stable because
|
||||||
|
* it was introduced as an alternative ABI for non-C software.
|
||||||
|
* https://github.com/WebAssembly/wasi-libc/pull/347
|
||||||
|
*/
|
||||||
|
#if defined(errno)
|
||||||
|
#undef errno
|
||||||
|
#endif
|
||||||
|
int *
|
||||||
|
__errno_location(void);
|
||||||
|
#define errno (*__errno_location())
|
||||||
|
|
||||||
#define HANDLE_ERROR(error) \
|
#define HANDLE_ERROR(error) \
|
||||||
if (error != __WASI_ERRNO_SUCCESS) { \
|
if (error != __WASI_ERRNO_SUCCESS) { \
|
||||||
errno = error; \
|
errno = error; \
|
||||||
|
|
|
@ -43,7 +43,7 @@ else()
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
uvwasi
|
uvwasi
|
||||||
GIT_REPOSITORY https://github.com/nodejs/uvwasi.git
|
GIT_REPOSITORY https://github.com/nodejs/uvwasi.git
|
||||||
GIT_TAG v0.0.21
|
GIT_TAG 392e1f1c1c8a2d2102c9f2e0b9f35959a149d133
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(uvwasi)
|
FetchContent_MakeAvailable(uvwasi)
|
||||||
include_directories("${uvwasi_SOURCE_DIR}/include")
|
include_directories("${uvwasi_SOURCE_DIR}/include")
|
||||||
|
|
|
@ -890,24 +890,6 @@ wasi_path_symlink(wasm_exec_env_t exec_env, const char *old_path,
|
||||||
if (!uvwasi)
|
if (!uvwasi)
|
||||||
return (wasi_errno_t)-1;
|
return (wasi_errno_t)-1;
|
||||||
|
|
||||||
/*
|
|
||||||
* check if old_path is valid.
|
|
||||||
* if it is a symlink, follow it.
|
|
||||||
*
|
|
||||||
* this is a workaround for the fact that
|
|
||||||
* uvwasi_path_symlink does not check if the old_path is valid
|
|
||||||
*
|
|
||||||
* the goal is trigger uvwasi__resolve_path() to check
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
uvwasi_filestat_t filestat = { 0 };
|
|
||||||
wasi_errno_t err =
|
|
||||||
uvwasi_path_filestat_get(uvwasi, fd, UVWASI_LOOKUP_SYMLINK_FOLLOW,
|
|
||||||
old_path, old_path_len, &filestat);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uvwasi_path_symlink(uvwasi, old_path, old_path_len, fd, new_path,
|
return uvwasi_path_symlink(uvwasi, old_path, old_path_len, fd, new_path,
|
||||||
new_path_len);
|
new_path_len);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ There is a big difference between the two sets of functions, `tensor_type`.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
typedef enum { fp16 = 0, fp32, fp64, bf16, u8, i32, i64 } tensor_type;
|
typedef enum { fp16 = 0, fp32, fp64, u8, i32, i64 } tensor_type;
|
||||||
#else
|
#else
|
||||||
typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type;
|
typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type;
|
||||||
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
||||||
|
|
12
core/iwasm/libraries/wasi-nn/include/wasi_ephemeral_nn.h
Normal file
12
core/iwasm/libraries/wasi-nn/include/wasi_ephemeral_nn.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WASM_ENABLE_WASI_EPHEMERAL_NN 1
|
||||||
|
#define WASI_NN_NAME(name) wasi_ephemeral_nn_##name
|
||||||
|
|
||||||
|
#include "wasi_nn.h"
|
||||||
|
|
||||||
|
#undef WASM_ENABLE_WASI_EPHEMERAL_NN
|
||||||
|
#undef WASI_NN_NAME
|
|
@ -15,23 +15,43 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "wasi_nn_types.h"
|
#include "wasi_nn_types.h"
|
||||||
|
|
||||||
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
|
#define WASI_NN_IMPORT(name) \
|
||||||
|
__attribute__((import_module("wasi_ephemeral_nn"), import_name(name)))
|
||||||
|
#else
|
||||||
|
#define WASI_NN_IMPORT(name) \
|
||||||
|
__attribute__((import_module("wasi_nn"), import_name(name)))
|
||||||
|
#warning You are using "wasi_nn", which is a legacy WAMR-specific ABI. It's deperecated and will likely be removed in future versions of WAMR. Please use "wasi_ephemeral_nn" instead. (For a WASM module, use the wasi_ephemeral_nn.h header instead. For the runtime configurations, enable WASM_ENABLE_WASI_EPHEMERAL_NN/WAMR_BUILD_WASI_EPHEMERAL_NN.)
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Load an opaque sequence of bytes to use for inference.
|
* @brief Load an opaque sequence of bytes to use for inference.
|
||||||
*
|
*
|
||||||
* @param builder Model builder.
|
* @param builder Model builder.
|
||||||
|
* @param builder_len The size of model builder.
|
||||||
* @param encoding Model encoding.
|
* @param encoding Model encoding.
|
||||||
* @param target Execution target.
|
* @param target Execution target.
|
||||||
* @param g Graph.
|
* @param g Graph.
|
||||||
* @return wasi_nn_error Execution status.
|
* @return wasi_nn_error Execution status.
|
||||||
*/
|
*/
|
||||||
wasi_nn_error
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
load(graph_builder_array *builder, graph_encoding encoding,
|
WASI_NN_ERROR_TYPE
|
||||||
execution_target target, graph *g)
|
WASI_NN_NAME(load)
|
||||||
__attribute__((import_module("wasi_nn")));
|
(WASI_NN_NAME(graph_builder) * builder, uint32_t builder_len,
|
||||||
|
WASI_NN_NAME(graph_encoding) encoding, WASI_NN_NAME(execution_target) target,
|
||||||
|
WASI_NN_NAME(graph) * g) WASI_NN_IMPORT("load");
|
||||||
|
#else
|
||||||
|
WASI_NN_ERROR_TYPE
|
||||||
|
WASI_NN_NAME(load)
|
||||||
|
(WASI_NN_NAME(graph_builder_array) * builder,
|
||||||
|
WASI_NN_NAME(graph_encoding) encoding, WASI_NN_NAME(execution_target) target,
|
||||||
|
WASI_NN_NAME(graph) * g) WASI_NN_IMPORT("load");
|
||||||
|
#endif
|
||||||
|
|
||||||
wasi_nn_error
|
WASI_NN_ERROR_TYPE
|
||||||
load_by_name(const char *name, graph *g)
|
WASI_NN_NAME(load_by_name)
|
||||||
__attribute__((import_module("wasi_nn")));
|
(const char *name, uint32_t name_len, WASI_NN_NAME(graph) * g)
|
||||||
|
WASI_NN_IMPORT("load_by_name");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INFERENCE
|
* INFERENCE
|
||||||
|
@ -45,9 +65,10 @@ load_by_name(const char *name, graph *g)
|
||||||
* @param ctx Execution context.
|
* @param ctx Execution context.
|
||||||
* @return wasi_nn_error Execution status.
|
* @return wasi_nn_error Execution status.
|
||||||
*/
|
*/
|
||||||
wasi_nn_error
|
WASI_NN_ERROR_TYPE
|
||||||
init_execution_context(graph g, graph_execution_context *ctx)
|
WASI_NN_NAME(init_execution_context)
|
||||||
__attribute__((import_module("wasi_nn")));
|
(WASI_NN_NAME(graph) g, WASI_NN_NAME(graph_execution_context) * ctx)
|
||||||
|
WASI_NN_IMPORT("init_execution_context");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Define the inputs to use for inference.
|
* @brief Define the inputs to use for inference.
|
||||||
|
@ -57,9 +78,10 @@ init_execution_context(graph g, graph_execution_context *ctx)
|
||||||
* @param tensor Input tensor.
|
* @param tensor Input tensor.
|
||||||
* @return wasi_nn_error Execution status.
|
* @return wasi_nn_error Execution status.
|
||||||
*/
|
*/
|
||||||
wasi_nn_error
|
WASI_NN_ERROR_TYPE
|
||||||
set_input(graph_execution_context ctx, uint32_t index, tensor *tensor)
|
WASI_NN_NAME(set_input)
|
||||||
__attribute__((import_module("wasi_nn")));
|
(WASI_NN_NAME(graph_execution_context) ctx, uint32_t index,
|
||||||
|
WASI_NN_NAME(tensor) * tensor) WASI_NN_IMPORT("set_input");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Compute the inference on the given inputs.
|
* @brief Compute the inference on the given inputs.
|
||||||
|
@ -67,8 +89,9 @@ set_input(graph_execution_context ctx, uint32_t index, tensor *tensor)
|
||||||
* @param ctx Execution context.
|
* @param ctx Execution context.
|
||||||
* @return wasi_nn_error Execution status.
|
* @return wasi_nn_error Execution status.
|
||||||
*/
|
*/
|
||||||
wasi_nn_error
|
WASI_NN_ERROR_TYPE
|
||||||
compute(graph_execution_context ctx) __attribute__((import_module("wasi_nn")));
|
WASI_NN_NAME(compute)
|
||||||
|
(WASI_NN_NAME(graph_execution_context) ctx) WASI_NN_IMPORT("compute");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Extract the outputs after inference.
|
* @brief Extract the outputs after inference.
|
||||||
|
@ -82,9 +105,17 @@ compute(graph_execution_context ctx) __attribute__((import_module("wasi_nn")));
|
||||||
* copied number of bytes.
|
* copied number of bytes.
|
||||||
* @return wasi_nn_error Execution status.
|
* @return wasi_nn_error Execution status.
|
||||||
*/
|
*/
|
||||||
wasi_nn_error
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
get_output(graph_execution_context ctx, uint32_t index,
|
WASI_NN_ERROR_TYPE
|
||||||
tensor_data output_tensor, uint32_t *output_tensor_size)
|
WASI_NN_NAME(get_output)
|
||||||
__attribute__((import_module("wasi_nn")));
|
(WASI_NN_NAME(graph_execution_context) ctx, uint32_t index,
|
||||||
|
uint8_t *output_tensor, uint32_t output_tensor_max_size,
|
||||||
|
uint32_t *output_tensor_size) WASI_NN_IMPORT("get_output");
|
||||||
|
#else
|
||||||
|
WASI_NN_ERROR_TYPE
|
||||||
|
WASI_NN_NAME(get_output)
|
||||||
|
(graph_execution_context ctx, uint32_t index, uint8_t *output_tensor,
|
||||||
|
uint32_t *output_tensor_size) WASI_NN_IMPORT("get_output");
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,42 +13,48 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* our host logic doesn't use any prefix. neither legacy wasi_nn.h does. */
|
||||||
|
|
||||||
|
#if !defined(__wasm__) || !defined(WASI_NN_NAME)
|
||||||
|
#define WASI_NN_NAME(name) name
|
||||||
|
#define WASI_NN_ERROR_NAME(name) name
|
||||||
|
#define WASI_NN_TYPE_NAME(name) name
|
||||||
|
#define WASI_NN_ENCODING_NAME(name) name
|
||||||
|
#define WASI_NN_TARGET_NAME(name) name
|
||||||
|
#define WASI_NN_ERROR_TYPE wasi_nn_error
|
||||||
|
#else
|
||||||
|
#define WASI_NN_ERROR_NAME(name) WASI_NN_NAME(error_##name)
|
||||||
|
#define WASI_NN_TYPE_NAME(name) WASI_NN_NAME(type_##name)
|
||||||
|
#define WASI_NN_ENCODING_NAME(name) WASI_NN_NAME(encoding_##name)
|
||||||
|
#define WASI_NN_TARGET_NAME(name) WASI_NN_NAME(target_##name)
|
||||||
|
#define WASI_NN_ERROR_TYPE WASI_NN_NAME(error);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ERRORS
|
* ERRORS
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// sync up with
|
// sync up with
|
||||||
// https://github.com/WebAssembly/wasi-nn/blob/main/wit/wasi-nn.wit#L136 Error
|
// https://github.com/WebAssembly/wasi-nn/blob/71320d95b8c6d43f9af7f44e18b1839db85d89b4/wasi-nn.witx#L5-L17
|
||||||
// codes returned by functions in this API.
|
// Error codes returned by functions in this API.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// No error occurred.
|
WASI_NN_ERROR_NAME(success) = 0,
|
||||||
success = 0,
|
WASI_NN_ERROR_NAME(invalid_argument),
|
||||||
// Caller module passed an invalid argument.
|
WASI_NN_ERROR_NAME(invalid_encoding),
|
||||||
invalid_argument,
|
WASI_NN_ERROR_NAME(missing_memory),
|
||||||
// Invalid encoding.
|
WASI_NN_ERROR_NAME(busy),
|
||||||
invalid_encoding,
|
WASI_NN_ERROR_NAME(runtime_error),
|
||||||
// The operation timed out.
|
WASI_NN_ERROR_NAME(unsupported_operation),
|
||||||
timeout,
|
WASI_NN_ERROR_NAME(too_large),
|
||||||
// Runtime Error.
|
WASI_NN_ERROR_NAME(not_found),
|
||||||
runtime_error,
|
|
||||||
// Unsupported operation.
|
|
||||||
unsupported_operation,
|
|
||||||
// Graph is too large.
|
|
||||||
too_large,
|
|
||||||
// Graph not found.
|
|
||||||
not_found,
|
|
||||||
// The operation is insecure or has insufficient privilege to be performed.
|
|
||||||
// e.g., cannot access a hardware feature requested
|
|
||||||
security,
|
|
||||||
// The operation failed for an unspecified reason.
|
|
||||||
unknown,
|
|
||||||
// for WasmEdge-wasi-nn
|
// for WasmEdge-wasi-nn
|
||||||
end_of_sequence = 100, // End of Sequence Found.
|
WASI_NN_ERROR_NAME(end_of_sequence) = 100, // End of Sequence Found.
|
||||||
context_full = 101, // Context Full.
|
WASI_NN_ERROR_NAME(context_full) = 101, // Context Full.
|
||||||
prompt_tool_long = 102, // Prompt Too Long.
|
WASI_NN_ERROR_NAME(prompt_tool_long) = 102, // Prompt Too Long.
|
||||||
model_not_found = 103, // Model Not Found.
|
WASI_NN_ERROR_NAME(model_not_found) = 103, // Model Not Found.
|
||||||
} wasi_nn_error;
|
} WASI_NN_ERROR_TYPE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TENSOR
|
* TENSOR
|
||||||
|
@ -62,15 +68,27 @@ typedef enum {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t *buf;
|
uint32_t *buf;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
} tensor_dimensions;
|
} WASI_NN_NAME(tensor_dimensions);
|
||||||
|
|
||||||
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
// sync up with
|
// sync up with
|
||||||
// https://github.com/WebAssembly/wasi-nn/blob/main/wit/wasi-nn.wit#L27
|
// https://github.com/WebAssembly/wasi-nn/blob/71320d95b8c6d43f9af7f44e18b1839db85d89b4/wasi-nn.witx#L19-L28
|
||||||
// The type of the elements in a tensor.
|
// The type of the elements in a tensor.
|
||||||
typedef enum { fp16 = 0, fp32, fp64, bf16, u8, i32, i64 } tensor_type;
|
typedef enum {
|
||||||
|
WASI_NN_TYPE_NAME(fp16) = 0,
|
||||||
|
WASI_NN_TYPE_NAME(fp32),
|
||||||
|
WASI_NN_TYPE_NAME(fp64),
|
||||||
|
WASI_NN_TYPE_NAME(u8),
|
||||||
|
WASI_NN_TYPE_NAME(i32),
|
||||||
|
WASI_NN_TYPE_NAME(i64),
|
||||||
|
} WASI_NN_NAME(tensor_type);
|
||||||
#else
|
#else
|
||||||
typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type;
|
typedef enum {
|
||||||
|
WASI_NN_TYPE_NAME(fp16) = 0,
|
||||||
|
WASI_NN_TYPE_NAME(fp32),
|
||||||
|
WASI_NN_TYPE_NAME(up8),
|
||||||
|
WASI_NN_TYPE_NAME(ip32),
|
||||||
|
} WASI_NN_NAME(tensor_type);
|
||||||
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
||||||
|
|
||||||
// The tensor data.
|
// The tensor data.
|
||||||
|
@ -81,19 +99,31 @@ typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type;
|
||||||
// 4-byte f32 elements would have a data array of length 16). Naturally, this
|
// 4-byte f32 elements would have a data array of length 16). Naturally, this
|
||||||
// representation requires some knowledge of how to lay out data in
|
// representation requires some knowledge of how to lay out data in
|
||||||
// memory--e.g., using row-major ordering--and could perhaps be improved.
|
// memory--e.g., using row-major ordering--and could perhaps be improved.
|
||||||
typedef uint8_t *tensor_data;
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 && defined(__wasm__)
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *buf;
|
||||||
|
uint32_t size;
|
||||||
|
} WASI_NN_NAME(tensor_data);
|
||||||
|
#else
|
||||||
|
typedef uint8_t *WASI_NN_NAME(tensor_data);
|
||||||
|
#endif
|
||||||
|
|
||||||
// A tensor.
|
// A tensor.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// Describe the size of the tensor (e.g., 2x2x2x2 -> [2, 2, 2, 2]). To
|
// Describe the size of the tensor (e.g., 2x2x2x2 -> [2, 2, 2, 2]). To
|
||||||
// represent a tensor containing a single value, use `[1]` for the tensor
|
// represent a tensor containing a single value, use `[1]` for the tensor
|
||||||
// dimensions.
|
// dimensions.
|
||||||
tensor_dimensions *dimensions;
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 && defined(__wasm__)
|
||||||
|
WASI_NN_NAME(tensor_dimensions) dimensions;
|
||||||
|
#else
|
||||||
|
WASI_NN_NAME(tensor_dimensions) * dimensions;
|
||||||
|
#endif
|
||||||
// Describe the type of element in the tensor (e.g., f32).
|
// Describe the type of element in the tensor (e.g., f32).
|
||||||
tensor_type type;
|
uint8_t type;
|
||||||
|
uint8_t _pad[3];
|
||||||
// Contains the tensor data.
|
// Contains the tensor data.
|
||||||
tensor_data data;
|
WASI_NN_NAME(tensor_data) data;
|
||||||
} tensor;
|
} WASI_NN_NAME(tensor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GRAPH
|
* GRAPH
|
||||||
|
@ -108,15 +138,15 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
} graph_builder;
|
} WASI_NN_NAME(graph_builder);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
graph_builder *buf;
|
WASI_NN_NAME(graph_builder) * buf;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
} graph_builder_array;
|
} WASI_NN_NAME(graph_builder_array);
|
||||||
|
|
||||||
// An execution graph for performing inference (i.e., a model).
|
// An execution graph for performing inference (i.e., a model).
|
||||||
typedef uint32_t graph;
|
typedef uint32_t WASI_NN_NAME(graph);
|
||||||
|
|
||||||
// sync up with
|
// sync up with
|
||||||
// https://github.com/WebAssembly/wasi-nn/blob/main/wit/wasi-nn.wit#L75
|
// https://github.com/WebAssembly/wasi-nn/blob/main/wit/wasi-nn.wit#L75
|
||||||
|
@ -124,56 +154,25 @@ typedef uint32_t graph;
|
||||||
// various backends that encode (i.e., serialize) their graph IR with different
|
// various backends that encode (i.e., serialize) their graph IR with different
|
||||||
// formats.
|
// formats.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
openvino = 0,
|
WASI_NN_ENCODING_NAME(openvino) = 0,
|
||||||
onnx,
|
WASI_NN_ENCODING_NAME(onnx),
|
||||||
tensorflow,
|
WASI_NN_ENCODING_NAME(tensorflow),
|
||||||
pytorch,
|
WASI_NN_ENCODING_NAME(pytorch),
|
||||||
tensorflowlite,
|
WASI_NN_ENCODING_NAME(tensorflowlite),
|
||||||
ggml,
|
WASI_NN_ENCODING_NAME(ggml),
|
||||||
autodetect,
|
WASI_NN_ENCODING_NAME(autodetect),
|
||||||
unknown_backend,
|
WASI_NN_ENCODING_NAME(unknown_backend),
|
||||||
} graph_encoding;
|
} WASI_NN_NAME(graph_encoding);
|
||||||
|
|
||||||
// Define where the graph should be executed.
|
// Define where the graph should be executed.
|
||||||
typedef enum execution_target { cpu = 0, gpu, tpu } execution_target;
|
typedef enum WASI_NN_NAME(execution_target) {
|
||||||
|
WASI_NN_TARGET_NAME(cpu) = 0,
|
||||||
|
WASI_NN_TARGET_NAME(gpu),
|
||||||
|
WASI_NN_TARGET_NAME(tpu),
|
||||||
|
} WASI_NN_NAME(execution_target);
|
||||||
|
|
||||||
// Bind a `graph` to the input and output tensors for an inference.
|
// Bind a `graph` to the input and output tensors for an inference.
|
||||||
typedef uint32_t graph_execution_context;
|
typedef uint32_t WASI_NN_NAME(graph_execution_context);
|
||||||
|
|
||||||
/* Definition of 'wasi_nn.h' structs in WASM app format (using offset) */
|
|
||||||
|
|
||||||
typedef wasi_nn_error (*LOAD)(void *, graph_builder_array *, graph_encoding,
|
|
||||||
execution_target, graph *);
|
|
||||||
typedef wasi_nn_error (*LOAD_BY_NAME)(void *, const char *, uint32_t, graph *);
|
|
||||||
typedef wasi_nn_error (*LOAD_BY_NAME_WITH_CONFIG)(void *, const char *,
|
|
||||||
uint32_t, void *, uint32_t,
|
|
||||||
graph *);
|
|
||||||
typedef wasi_nn_error (*INIT_EXECUTION_CONTEXT)(void *, graph,
|
|
||||||
graph_execution_context *);
|
|
||||||
typedef wasi_nn_error (*SET_INPUT)(void *, graph_execution_context, uint32_t,
|
|
||||||
tensor *);
|
|
||||||
typedef wasi_nn_error (*COMPUTE)(void *, graph_execution_context);
|
|
||||||
typedef wasi_nn_error (*GET_OUTPUT)(void *, graph_execution_context, uint32_t,
|
|
||||||
tensor_data, uint32_t *);
|
|
||||||
/* wasi-nn general APIs */
|
|
||||||
typedef wasi_nn_error (*BACKEND_INITIALIZE)(void **);
|
|
||||||
typedef wasi_nn_error (*BACKEND_DEINITIALIZE)(void *);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
LOAD load;
|
|
||||||
LOAD_BY_NAME load_by_name;
|
|
||||||
LOAD_BY_NAME_WITH_CONFIG load_by_name_with_config;
|
|
||||||
INIT_EXECUTION_CONTEXT init_execution_context;
|
|
||||||
SET_INPUT set_input;
|
|
||||||
COMPUTE compute;
|
|
||||||
GET_OUTPUT get_output;
|
|
||||||
BACKEND_INITIALIZE init;
|
|
||||||
BACKEND_DEINITIALIZE deinit;
|
|
||||||
} api_function;
|
|
||||||
|
|
||||||
void
|
|
||||||
wasi_nn_dump_tensor_dimension(tensor_dimensions *dim, int32_t output_len,
|
|
||||||
char *output);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,29 @@
|
||||||
#include "wasi_nn_types.h"
|
#include "wasi_nn_types.h"
|
||||||
#include "wasm_export.h"
|
#include "wasm_export.h"
|
||||||
|
|
||||||
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN == 0
|
||||||
|
#warning You are using "wasi_nn", which is a legacy WAMR-specific ABI. It's deperecated and will likely be removed in future versions of WAMR. Please use "wasi_ephemeral_nn" instead. (For a WASM module, use the wasi_ephemeral_nn.h header instead. For the runtime configurations, enable WASM_ENABLE_WASI_EPHEMERAL_NN/WAMR_BUILD_WASI_EPHEMERAL_NN.)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define HASHMAP_INITIAL_SIZE 20
|
#define HASHMAP_INITIAL_SIZE 20
|
||||||
#define TFLITE_BACKEND_LIB "libwasi_nn_tflite.so"
|
#if defined(__APPLE__)
|
||||||
#define OPENVINO_BACKEND_LIB "libwasi_nn_openvino.so"
|
#define LIB_EXTENTION ".dylib"
|
||||||
#define LLAMACPP_BACKEND_LIB "libwasi_nn_llamacpp.so"
|
#else
|
||||||
|
#define LIB_EXTENTION ".so"
|
||||||
|
#endif
|
||||||
|
#define TFLITE_BACKEND_LIB "libwasi_nn_tflite" LIB_EXTENTION
|
||||||
|
#define OPENVINO_BACKEND_LIB "libwasi_nn_openvino" LIB_EXTENTION
|
||||||
|
#define LLAMACPP_BACKEND_LIB "libwasi_nn_llamacpp" LIB_EXTENTION
|
||||||
|
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
|
static korp_mutex wasi_nn_lock;
|
||||||
|
/*
|
||||||
|
* the "lookup" table is protected by wasi_nn_lock.
|
||||||
|
*
|
||||||
|
* an exception: during wasm_runtime_destroy, wasi_nn_destroy tears down
|
||||||
|
* the table without acquiring the lock. it's ok because there should be
|
||||||
|
* no other threads using the runtime at this point.
|
||||||
|
*/
|
||||||
struct backends_api_functions {
|
struct backends_api_functions {
|
||||||
void *backend_handle;
|
void *backend_handle;
|
||||||
api_function functions;
|
api_function functions;
|
||||||
|
@ -38,65 +55,36 @@ struct backends_api_functions {
|
||||||
NN_ERR_PRINTF("Error %s() -> %d", #func, wasi_error); \
|
NN_ERR_PRINTF("Error %s() -> %d", #func, wasi_error); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* HashMap utils */
|
static void *wasi_nn_key;
|
||||||
static HashMap *hashmap;
|
|
||||||
|
|
||||||
static uint32
|
|
||||||
hash_func(const void *key)
|
|
||||||
{
|
|
||||||
// fnv1a_hash
|
|
||||||
const uint32 FNV_PRIME = 16777619;
|
|
||||||
const uint32 FNV_OFFSET_BASIS = 2166136261U;
|
|
||||||
|
|
||||||
uint32 hash = FNV_OFFSET_BASIS;
|
|
||||||
const unsigned char *bytes = (const unsigned char *)key;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
|
|
||||||
hash ^= bytes[i];
|
|
||||||
hash *= FNV_PRIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
key_equal_func(void *key1, void *key2)
|
|
||||||
{
|
|
||||||
return key1 == key2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
key_destroy_func(void *key1)
|
|
||||||
{
|
|
||||||
/* key type is wasm_module_inst_t*. do nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wasi_nn_ctx_destroy(WASINNContext *wasi_nn_ctx)
|
wasi_nn_ctx_destroy(WASINNContext *wasi_nn_ctx)
|
||||||
{
|
{
|
||||||
NN_DBG_PRINTF("[WASI NN] DEINIT...");
|
|
||||||
|
|
||||||
if (wasi_nn_ctx == NULL) {
|
if (wasi_nn_ctx == NULL) {
|
||||||
NN_ERR_PRINTF(
|
|
||||||
"Error when deallocating memory. WASI-NN context is NULL");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
NN_DBG_PRINTF("[WASI NN] DEINIT...");
|
||||||
NN_DBG_PRINTF("Freeing wasi-nn");
|
NN_DBG_PRINTF("Freeing wasi-nn");
|
||||||
NN_DBG_PRINTF("-> is_model_loaded: %d", wasi_nn_ctx->is_model_loaded);
|
NN_DBG_PRINTF("-> is_model_loaded: %d", wasi_nn_ctx->is_model_loaded);
|
||||||
NN_DBG_PRINTF("-> current_encoding: %d", wasi_nn_ctx->backend);
|
NN_DBG_PRINTF("-> current_encoding: %d", wasi_nn_ctx->backend);
|
||||||
|
|
||||||
/* deinit() the backend */
|
bh_assert(!wasi_nn_ctx->busy);
|
||||||
wasi_nn_error res;
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, deinit, res,
|
|
||||||
wasi_nn_ctx->backend_ctx);
|
|
||||||
|
|
||||||
|
/* deinit() the backend */
|
||||||
|
if (wasi_nn_ctx->is_backend_ctx_initialized) {
|
||||||
|
wasi_nn_error res;
|
||||||
|
call_wasi_nn_func(wasi_nn_ctx->backend, deinit, res,
|
||||||
|
wasi_nn_ctx->backend_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
os_mutex_destroy(&wasi_nn_ctx->lock);
|
||||||
wasm_runtime_free(wasi_nn_ctx);
|
wasm_runtime_free(wasi_nn_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
value_destroy_func(void *value)
|
dtor(wasm_module_inst_t inst, void *ctx)
|
||||||
{
|
{
|
||||||
wasi_nn_ctx_destroy((WASINNContext *)value);
|
wasi_nn_ctx_destroy(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -104,12 +92,15 @@ wasi_nn_initialize()
|
||||||
{
|
{
|
||||||
NN_DBG_PRINTF("[WASI NN General] Initializing wasi-nn");
|
NN_DBG_PRINTF("[WASI NN General] Initializing wasi-nn");
|
||||||
|
|
||||||
// hashmap { instance: wasi_nn_ctx }
|
if (os_mutex_init(&wasi_nn_lock)) {
|
||||||
hashmap = bh_hash_map_create(HASHMAP_INITIAL_SIZE, true, hash_func,
|
NN_ERR_PRINTF("Error while initializing global lock");
|
||||||
key_equal_func, key_destroy_func,
|
return false;
|
||||||
value_destroy_func);
|
}
|
||||||
if (hashmap == NULL) {
|
|
||||||
NN_ERR_PRINTF("Error while initializing hashmap");
|
wasi_nn_key = wasm_runtime_create_context_key(dtor);
|
||||||
|
if (wasi_nn_key == NULL) {
|
||||||
|
NN_ERR_PRINTF("Failed to create context key");
|
||||||
|
os_mutex_destroy(&wasi_nn_lock);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +120,11 @@ wasi_nn_initialize_context()
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(wasi_nn_ctx, 0, sizeof(WASINNContext));
|
memset(wasi_nn_ctx, 0, sizeof(WASINNContext));
|
||||||
|
if (os_mutex_init(&wasi_nn_ctx->lock)) {
|
||||||
|
NN_ERR_PRINTF("Error when initializing a lock for WASI-NN context");
|
||||||
|
wasm_runtime_free(wasi_nn_ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return wasi_nn_ctx;
|
return wasi_nn_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,29 +133,59 @@ static WASINNContext *
|
||||||
wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance)
|
wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance)
|
||||||
{
|
{
|
||||||
WASINNContext *wasi_nn_ctx =
|
WASINNContext *wasi_nn_ctx =
|
||||||
(WASINNContext *)bh_hash_map_find(hashmap, (void *)instance);
|
wasm_runtime_get_context(instance, wasi_nn_key);
|
||||||
if (wasi_nn_ctx == NULL) {
|
if (wasi_nn_ctx == NULL) {
|
||||||
wasi_nn_ctx = wasi_nn_initialize_context();
|
WASINNContext *newctx = wasi_nn_initialize_context();
|
||||||
if (wasi_nn_ctx == NULL)
|
if (newctx == NULL)
|
||||||
return NULL;
|
|
||||||
|
|
||||||
bool ok =
|
|
||||||
bh_hash_map_insert(hashmap, (void *)instance, (void *)wasi_nn_ctx);
|
|
||||||
if (!ok) {
|
|
||||||
NN_ERR_PRINTF("Error while storing context");
|
|
||||||
wasi_nn_ctx_destroy(wasi_nn_ctx);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
os_mutex_lock(&wasi_nn_lock);
|
||||||
|
wasi_nn_ctx = wasm_runtime_get_context(instance, wasi_nn_key);
|
||||||
|
if (wasi_nn_ctx == NULL) {
|
||||||
|
wasm_runtime_set_context_spread(instance, wasi_nn_key, newctx);
|
||||||
|
wasi_nn_ctx = newctx;
|
||||||
|
newctx = NULL;
|
||||||
|
}
|
||||||
|
os_mutex_unlock(&wasi_nn_lock);
|
||||||
|
if (newctx != NULL) {
|
||||||
|
wasi_nn_ctx_destroy(newctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return wasi_nn_ctx;
|
return wasi_nn_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WASINNContext *
|
||||||
|
lock_ctx(wasm_module_inst_t instance)
|
||||||
|
{
|
||||||
|
WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance);
|
||||||
|
if (wasi_nn_ctx == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
os_mutex_lock(&wasi_nn_ctx->lock);
|
||||||
|
if (wasi_nn_ctx->busy) {
|
||||||
|
os_mutex_unlock(&wasi_nn_ctx->lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
wasi_nn_ctx->busy = true;
|
||||||
|
os_mutex_unlock(&wasi_nn_ctx->lock);
|
||||||
|
return wasi_nn_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unlock_ctx(WASINNContext *wasi_nn_ctx)
|
||||||
|
{
|
||||||
|
if (wasi_nn_ctx == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
os_mutex_lock(&wasi_nn_ctx->lock);
|
||||||
|
bh_assert(wasi_nn_ctx->busy);
|
||||||
|
wasi_nn_ctx->busy = false;
|
||||||
|
os_mutex_unlock(&wasi_nn_ctx->lock);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wasi_nn_destroy()
|
wasi_nn_destroy()
|
||||||
{
|
{
|
||||||
// destroy hashmap will destroy keys and values
|
wasm_runtime_destroy_context_key(wasi_nn_key);
|
||||||
bh_hash_map_destroy(hashmap);
|
|
||||||
|
|
||||||
// close backends' libraries and registered functions
|
// close backends' libraries and registered functions
|
||||||
for (unsigned i = 0; i < sizeof(lookup) / sizeof(lookup[0]); i++) {
|
for (unsigned i = 0; i < sizeof(lookup) / sizeof(lookup[0]); i++) {
|
||||||
|
@ -170,6 +196,8 @@ wasi_nn_destroy()
|
||||||
|
|
||||||
memset(&lookup[i].functions, 0, sizeof(api_function));
|
memset(&lookup[i].functions, 0, sizeof(api_function));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
os_mutex_destroy(&wasi_nn_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Utils */
|
/* Utils */
|
||||||
|
@ -342,9 +370,10 @@ graph_encoding_to_backend_lib_name(graph_encoding encoding)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
detect_and_load_backend(graph_encoding backend_hint,
|
detect_and_load_backend(graph_encoding backend_hint,
|
||||||
struct backends_api_functions *backends,
|
|
||||||
graph_encoding *loaded_backend)
|
graph_encoding *loaded_backend)
|
||||||
{
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
if (backend_hint > autodetect)
|
if (backend_hint > autodetect)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -356,16 +385,58 @@ detect_and_load_backend(graph_encoding backend_hint,
|
||||||
|
|
||||||
*loaded_backend = backend_hint;
|
*loaded_backend = backend_hint;
|
||||||
|
|
||||||
|
os_mutex_lock(&wasi_nn_lock);
|
||||||
/* if already loaded */
|
/* if already loaded */
|
||||||
if (lookup[backend_hint].backend_handle)
|
if (lookup[backend_hint].backend_handle) {
|
||||||
|
os_mutex_unlock(&wasi_nn_lock);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const char *backend_lib_name =
|
const char *backend_lib_name =
|
||||||
graph_encoding_to_backend_lib_name(backend_hint);
|
graph_encoding_to_backend_lib_name(backend_hint);
|
||||||
if (!backend_lib_name)
|
if (!backend_lib_name) {
|
||||||
|
os_mutex_unlock(&wasi_nn_lock);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return prepare_backend(backend_lib_name, backends + backend_hint);
|
ret = prepare_backend(backend_lib_name, lookup + backend_hint);
|
||||||
|
os_mutex_unlock(&wasi_nn_lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static wasi_nn_error
|
||||||
|
ensure_backend(wasm_module_inst_t instance, graph_encoding encoding,
|
||||||
|
WASINNContext *wasi_nn_ctx)
|
||||||
|
{
|
||||||
|
wasi_nn_error res;
|
||||||
|
|
||||||
|
graph_encoding loaded_backend = autodetect;
|
||||||
|
if (!detect_and_load_backend(encoding, &loaded_backend)) {
|
||||||
|
res = invalid_encoding;
|
||||||
|
NN_ERR_PRINTF("load backend failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wasi_nn_ctx->is_backend_ctx_initialized) {
|
||||||
|
if (wasi_nn_ctx->backend != loaded_backend) {
|
||||||
|
res = unsupported_operation;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wasi_nn_ctx->backend = loaded_backend;
|
||||||
|
|
||||||
|
/* init() the backend */
|
||||||
|
call_wasi_nn_func(wasi_nn_ctx->backend, init, res,
|
||||||
|
&wasi_nn_ctx->backend_ctx);
|
||||||
|
if (res != success)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
wasi_nn_ctx->is_backend_ctx_initialized = true;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
fail:
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WASI-NN implementation */
|
/* WASI-NN implementation */
|
||||||
|
@ -381,6 +452,8 @@ wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder,
|
||||||
graph_encoding encoding, execution_target target, graph *g)
|
graph_encoding encoding, execution_target target, graph *g)
|
||||||
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
||||||
{
|
{
|
||||||
|
wasi_nn_error res;
|
||||||
|
|
||||||
NN_DBG_PRINTF("[WASI NN] LOAD [encoding=%d, target=%d]...", encoding,
|
NN_DBG_PRINTF("[WASI NN] LOAD [encoding=%d, target=%d]...", encoding,
|
||||||
target);
|
target);
|
||||||
|
|
||||||
|
@ -388,18 +461,23 @@ wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder,
|
||||||
if (!instance)
|
if (!instance)
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
|
|
||||||
wasi_nn_error res;
|
WASINNContext *wasi_nn_ctx = lock_ctx(instance);
|
||||||
|
if (wasi_nn_ctx == NULL) {
|
||||||
|
res = busy;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
graph_builder_array builder_native = { 0 };
|
graph_builder_array builder_native = { 0 };
|
||||||
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
if (success
|
if (success
|
||||||
!= (res = graph_builder_array_app_native(
|
!= (res = graph_builder_array_app_native(
|
||||||
instance, builder, builder_wasm_size, &builder_native)))
|
instance, builder, builder_wasm_size, &builder_native)))
|
||||||
return res;
|
goto fail;
|
||||||
#else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */
|
#else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */
|
||||||
if (success
|
if (success
|
||||||
!= (res = graph_builder_array_app_native(instance, builder,
|
!= (res = graph_builder_array_app_native(instance, builder,
|
||||||
&builder_native)))
|
&builder_native)))
|
||||||
return res;
|
goto fail;
|
||||||
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
||||||
|
|
||||||
if (!wasm_runtime_validate_native_addr(instance, g,
|
if (!wasm_runtime_validate_native_addr(instance, g,
|
||||||
|
@ -409,19 +487,7 @@ wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
graph_encoding loaded_backend = autodetect;
|
res = ensure_backend(instance, encoding, wasi_nn_ctx);
|
||||||
if (!detect_and_load_backend(encoding, lookup, &loaded_backend)) {
|
|
||||||
res = invalid_encoding;
|
|
||||||
NN_ERR_PRINTF("load backend failed");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance);
|
|
||||||
wasi_nn_ctx->backend = loaded_backend;
|
|
||||||
|
|
||||||
/* init() the backend */
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, init, res,
|
|
||||||
&wasi_nn_ctx->backend_ctx);
|
|
||||||
if (res != success)
|
if (res != success)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -436,6 +502,7 @@ fail:
|
||||||
// XXX: Free intermediate structure pointers
|
// XXX: Free intermediate structure pointers
|
||||||
if (builder_native.buf)
|
if (builder_native.buf)
|
||||||
wasm_runtime_free(builder_native.buf);
|
wasm_runtime_free(builder_native.buf);
|
||||||
|
unlock_ctx(wasi_nn_ctx);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -444,6 +511,8 @@ wasi_nn_error
|
||||||
wasi_nn_load_by_name(wasm_exec_env_t exec_env, char *name, uint32_t name_len,
|
wasi_nn_load_by_name(wasm_exec_env_t exec_env, char *name, uint32_t name_len,
|
||||||
graph *g)
|
graph *g)
|
||||||
{
|
{
|
||||||
|
wasi_nn_error res;
|
||||||
|
|
||||||
wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env);
|
wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
|
@ -467,30 +536,26 @@ wasi_nn_load_by_name(wasm_exec_env_t exec_env, char *name, uint32_t name_len,
|
||||||
|
|
||||||
NN_DBG_PRINTF("[WASI NN] LOAD_BY_NAME %s...", name);
|
NN_DBG_PRINTF("[WASI NN] LOAD_BY_NAME %s...", name);
|
||||||
|
|
||||||
graph_encoding loaded_backend = autodetect;
|
WASINNContext *wasi_nn_ctx = lock_ctx(instance);
|
||||||
if (!detect_and_load_backend(autodetect, lookup, &loaded_backend)) {
|
if (wasi_nn_ctx == NULL) {
|
||||||
NN_ERR_PRINTF("load backend failed");
|
res = busy;
|
||||||
return invalid_encoding;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance);
|
res = ensure_backend(instance, autodetect, wasi_nn_ctx);
|
||||||
wasi_nn_ctx->backend = loaded_backend;
|
|
||||||
|
|
||||||
wasi_nn_error res;
|
|
||||||
/* init() the backend */
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, init, res,
|
|
||||||
&wasi_nn_ctx->backend_ctx);
|
|
||||||
if (res != success)
|
if (res != success)
|
||||||
return res;
|
goto fail;
|
||||||
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, load_by_name, res,
|
call_wasi_nn_func(wasi_nn_ctx->backend, load_by_name, res,
|
||||||
wasi_nn_ctx->backend_ctx, name, name_len, g);
|
wasi_nn_ctx->backend_ctx, name, name_len, g);
|
||||||
if (res != success)
|
if (res != success)
|
||||||
return res;
|
goto fail;
|
||||||
|
|
||||||
wasi_nn_ctx->backend = loaded_backend;
|
|
||||||
wasi_nn_ctx->is_model_loaded = true;
|
wasi_nn_ctx->is_model_loaded = true;
|
||||||
return success;
|
res = success;
|
||||||
|
fail:
|
||||||
|
unlock_ctx(wasi_nn_ctx);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
wasi_nn_error
|
wasi_nn_error
|
||||||
|
@ -498,6 +563,8 @@ wasi_nn_load_by_name_with_config(wasm_exec_env_t exec_env, char *name,
|
||||||
int32_t name_len, char *config,
|
int32_t name_len, char *config,
|
||||||
int32_t config_len, graph *g)
|
int32_t config_len, graph *g)
|
||||||
{
|
{
|
||||||
|
wasi_nn_error res;
|
||||||
|
|
||||||
wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env);
|
wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
|
@ -526,31 +593,28 @@ wasi_nn_load_by_name_with_config(wasm_exec_env_t exec_env, char *name,
|
||||||
|
|
||||||
NN_DBG_PRINTF("[WASI NN] LOAD_BY_NAME_WITH_CONFIG %s %s...", name, config);
|
NN_DBG_PRINTF("[WASI NN] LOAD_BY_NAME_WITH_CONFIG %s %s...", name, config);
|
||||||
|
|
||||||
graph_encoding loaded_backend = autodetect;
|
WASINNContext *wasi_nn_ctx = lock_ctx(instance);
|
||||||
if (!detect_and_load_backend(autodetect, lookup, &loaded_backend)) {
|
if (wasi_nn_ctx == NULL) {
|
||||||
NN_ERR_PRINTF("load backend failed");
|
res = busy;
|
||||||
return invalid_encoding;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance);
|
res = ensure_backend(instance, autodetect, wasi_nn_ctx);
|
||||||
wasi_nn_ctx->backend = loaded_backend;
|
|
||||||
|
|
||||||
wasi_nn_error res;
|
|
||||||
/* init() the backend */
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, init, res,
|
|
||||||
&wasi_nn_ctx->backend_ctx);
|
|
||||||
if (res != success)
|
if (res != success)
|
||||||
return res;
|
goto fail;
|
||||||
|
;
|
||||||
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, load_by_name_with_config, res,
|
call_wasi_nn_func(wasi_nn_ctx->backend, load_by_name_with_config, res,
|
||||||
wasi_nn_ctx->backend_ctx, name, name_len, config,
|
wasi_nn_ctx->backend_ctx, name, name_len, config,
|
||||||
config_len, g);
|
config_len, g);
|
||||||
if (res != success)
|
if (res != success)
|
||||||
return res;
|
goto fail;
|
||||||
|
|
||||||
wasi_nn_ctx->backend = loaded_backend;
|
|
||||||
wasi_nn_ctx->is_model_loaded = true;
|
wasi_nn_ctx->is_model_loaded = true;
|
||||||
return success;
|
res = success;
|
||||||
|
fail:
|
||||||
|
unlock_ctx(wasi_nn_ctx);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
wasi_nn_error
|
wasi_nn_error
|
||||||
|
@ -564,20 +628,27 @@ wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph g,
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance);
|
|
||||||
|
|
||||||
wasi_nn_error res;
|
wasi_nn_error res;
|
||||||
|
WASINNContext *wasi_nn_ctx = lock_ctx(instance);
|
||||||
|
if (wasi_nn_ctx == NULL) {
|
||||||
|
res = busy;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (success != (res = is_model_initialized(wasi_nn_ctx)))
|
if (success != (res = is_model_initialized(wasi_nn_ctx)))
|
||||||
return res;
|
goto fail;
|
||||||
|
|
||||||
if (!wasm_runtime_validate_native_addr(
|
if (!wasm_runtime_validate_native_addr(
|
||||||
instance, ctx, (uint64)sizeof(graph_execution_context))) {
|
instance, ctx, (uint64)sizeof(graph_execution_context))) {
|
||||||
NN_ERR_PRINTF("ctx is invalid");
|
NN_ERR_PRINTF("ctx is invalid");
|
||||||
return invalid_argument;
|
res = invalid_argument;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, init_execution_context, res,
|
call_wasi_nn_func(wasi_nn_ctx->backend, init_execution_context, res,
|
||||||
wasi_nn_ctx->backend_ctx, g, ctx);
|
wasi_nn_ctx->backend_ctx, g, ctx);
|
||||||
|
fail:
|
||||||
|
unlock_ctx(wasi_nn_ctx);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,17 +663,21 @@ wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx,
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance);
|
|
||||||
|
|
||||||
wasi_nn_error res;
|
wasi_nn_error res;
|
||||||
|
WASINNContext *wasi_nn_ctx = lock_ctx(instance);
|
||||||
|
if (wasi_nn_ctx == NULL) {
|
||||||
|
res = busy;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (success != (res = is_model_initialized(wasi_nn_ctx)))
|
if (success != (res = is_model_initialized(wasi_nn_ctx)))
|
||||||
return res;
|
goto fail;
|
||||||
|
|
||||||
tensor input_tensor_native = { 0 };
|
tensor input_tensor_native = { 0 };
|
||||||
if (success
|
if (success
|
||||||
!= (res = tensor_app_native(instance, input_tensor,
|
!= (res = tensor_app_native(instance, input_tensor,
|
||||||
&input_tensor_native)))
|
&input_tensor_native)))
|
||||||
return res;
|
goto fail;
|
||||||
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, set_input, res,
|
call_wasi_nn_func(wasi_nn_ctx->backend, set_input, res,
|
||||||
wasi_nn_ctx->backend_ctx, ctx, index,
|
wasi_nn_ctx->backend_ctx, ctx, index,
|
||||||
|
@ -610,7 +685,8 @@ wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx,
|
||||||
// XXX: Free intermediate structure pointers
|
// XXX: Free intermediate structure pointers
|
||||||
if (input_tensor_native.dimensions)
|
if (input_tensor_native.dimensions)
|
||||||
wasm_runtime_free(input_tensor_native.dimensions);
|
wasm_runtime_free(input_tensor_native.dimensions);
|
||||||
|
fail:
|
||||||
|
unlock_ctx(wasi_nn_ctx);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,14 +700,20 @@ wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx)
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance);
|
|
||||||
|
|
||||||
wasi_nn_error res;
|
wasi_nn_error res;
|
||||||
|
WASINNContext *wasi_nn_ctx = lock_ctx(instance);
|
||||||
|
if (wasi_nn_ctx == NULL) {
|
||||||
|
res = busy;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (success != (res = is_model_initialized(wasi_nn_ctx)))
|
if (success != (res = is_model_initialized(wasi_nn_ctx)))
|
||||||
return res;
|
goto fail;
|
||||||
|
|
||||||
call_wasi_nn_func(wasi_nn_ctx->backend, compute, res,
|
call_wasi_nn_func(wasi_nn_ctx->backend, compute, res,
|
||||||
wasi_nn_ctx->backend_ctx, ctx);
|
wasi_nn_ctx->backend_ctx, ctx);
|
||||||
|
fail:
|
||||||
|
unlock_ctx(wasi_nn_ctx);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,16 +736,21 @@ wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx,
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance);
|
|
||||||
|
|
||||||
wasi_nn_error res;
|
wasi_nn_error res;
|
||||||
|
WASINNContext *wasi_nn_ctx = lock_ctx(instance);
|
||||||
|
if (wasi_nn_ctx == NULL) {
|
||||||
|
res = busy;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (success != (res = is_model_initialized(wasi_nn_ctx)))
|
if (success != (res = is_model_initialized(wasi_nn_ctx)))
|
||||||
return res;
|
goto fail;
|
||||||
|
|
||||||
if (!wasm_runtime_validate_native_addr(instance, output_tensor_size,
|
if (!wasm_runtime_validate_native_addr(instance, output_tensor_size,
|
||||||
(uint64)sizeof(uint32_t))) {
|
(uint64)sizeof(uint32_t))) {
|
||||||
NN_ERR_PRINTF("output_tensor_size is invalid");
|
NN_ERR_PRINTF("output_tensor_size is invalid");
|
||||||
return invalid_argument;
|
res = invalid_argument;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
|
@ -676,6 +763,8 @@ wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx,
|
||||||
wasi_nn_ctx->backend_ctx, ctx, index, output_tensor,
|
wasi_nn_ctx->backend_ctx, ctx, index, output_tensor,
|
||||||
output_tensor_size);
|
output_tensor_size);
|
||||||
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
#endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */
|
||||||
|
fail:
|
||||||
|
unlock_ctx(wasi_nn_ctx);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,6 +786,7 @@ static NativeSymbol native_symbols_wasi_nn[] = {
|
||||||
REG_NATIVE_FUNC(get_output, "(ii*i*)i"),
|
REG_NATIVE_FUNC(get_output, "(ii*i*)i"),
|
||||||
#else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */
|
#else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */
|
||||||
REG_NATIVE_FUNC(load, "(*ii*)i"),
|
REG_NATIVE_FUNC(load, "(*ii*)i"),
|
||||||
|
REG_NATIVE_FUNC(load_by_name, "(*i*)i"),
|
||||||
REG_NATIVE_FUNC(init_execution_context, "(i*)i"),
|
REG_NATIVE_FUNC(init_execution_context, "(i*)i"),
|
||||||
REG_NATIVE_FUNC(set_input, "(ii*)i"),
|
REG_NATIVE_FUNC(set_input, "(ii*)i"),
|
||||||
REG_NATIVE_FUNC(compute, "(i)i"),
|
REG_NATIVE_FUNC(compute, "(i)i"),
|
||||||
|
|
|
@ -26,17 +26,25 @@
|
||||||
* from 4. to 6. is the Inference Loop
|
* from 4. to 6. is the Inference Loop
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* these limits are arbitrary. */
|
||||||
|
#define MAX_GRAPHS 4
|
||||||
|
#define MAX_EXECUTION_CONTEXTS 4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ov_core_t *core;
|
ov_core_t *core;
|
||||||
/* keep input model files */
|
/* keep input model files */
|
||||||
void *weight_data;
|
struct OpenVINOGraph {
|
||||||
ov_tensor_t *weights_tensor;
|
void *weight_data;
|
||||||
ov_model_t *model;
|
ov_tensor_t *weights_tensor;
|
||||||
/* add prepostprocess */
|
ov_model_t *model;
|
||||||
ov_model_t *new_model;
|
ov_compiled_model_t *compiled_model;
|
||||||
ov_compiled_model_t *compiled_model;
|
} graphs[MAX_GRAPHS];
|
||||||
ov_infer_request_t *infer_request;
|
struct OpenVINOExecutionContext {
|
||||||
ov_tensor_t *input_tensor;
|
struct OpenVINOGraph *graph;
|
||||||
|
ov_infer_request_t *infer_request;
|
||||||
|
} execution_contexts[MAX_EXECUTION_CONTEXTS];
|
||||||
|
unsigned int n_graphs;
|
||||||
|
unsigned int n_execution_contexts;
|
||||||
} OpenVINOContext;
|
} OpenVINOContext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -58,7 +66,7 @@ dump_ov_shape_t(const ov_shape_t *shape, int32_t output_len, char *output)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ret = snprintf(output, output_len, "%ld,[", shape->rank);
|
ret = snprintf(output, output_len, "%" PRId64 ",[", shape->rank);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -66,7 +74,7 @@ dump_ov_shape_t(const ov_shape_t *shape, int32_t output_len, char *output)
|
||||||
output += ret;
|
output += ret;
|
||||||
|
|
||||||
for (unsigned i = 0; i < shape->rank && output_len; i++) {
|
for (unsigned i = 0; i < shape->rank && output_len; i++) {
|
||||||
ret = snprintf(output, output_len, " %ld", shape->dims[i]);
|
ret = snprintf(output, output_len, " %" PRId64, shape->dims[i]);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -161,8 +169,6 @@ wasi_nn_tensor_type_to_openvino_element_type(tensor_type wasi_nn_type)
|
||||||
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
case fp64:
|
case fp64:
|
||||||
return F64;
|
return F64;
|
||||||
case bf16:
|
|
||||||
return BF16;
|
|
||||||
case i64:
|
case i64:
|
||||||
return I64;
|
return I64;
|
||||||
case u8:
|
case u8:
|
||||||
|
@ -183,6 +189,29 @@ wasi_nn_tensor_type_to_openvino_element_type(tensor_type wasi_nn_type)
|
||||||
return UNDEFINED;
|
return UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_graph(struct OpenVINOGraph *graph)
|
||||||
|
{
|
||||||
|
if (graph->weight_data)
|
||||||
|
os_free(graph->weight_data);
|
||||||
|
|
||||||
|
if (graph->weights_tensor)
|
||||||
|
ov_tensor_free(graph->weights_tensor);
|
||||||
|
|
||||||
|
if (graph->model)
|
||||||
|
ov_model_free(graph->model);
|
||||||
|
|
||||||
|
if (graph->compiled_model)
|
||||||
|
ov_compiled_model_free(graph->compiled_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_execution_context(struct OpenVINOExecutionContext *c)
|
||||||
|
{
|
||||||
|
if (c->infer_request)
|
||||||
|
ov_infer_request_free(c->infer_request);
|
||||||
|
}
|
||||||
|
|
||||||
static wasi_nn_error
|
static wasi_nn_error
|
||||||
uint32_array_to_int64_array(uint32_t array_size, uint32_t *src, int64_t **dst)
|
uint32_array_to_int64_array(uint32_t array_size, uint32_t *src, int64_t **dst)
|
||||||
{
|
{
|
||||||
|
@ -202,6 +231,8 @@ load(void *ctx, graph_builder_array *builder, graph_encoding encoding,
|
||||||
execution_target target, graph *g)
|
execution_target target, graph *g)
|
||||||
{
|
{
|
||||||
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
||||||
|
struct OpenVINOGraph *graph;
|
||||||
|
unsigned int graph_idx;
|
||||||
wasi_nn_error ret = unsupported_operation;
|
wasi_nn_error ret = unsupported_operation;
|
||||||
|
|
||||||
if (encoding != openvino) {
|
if (encoding != openvino) {
|
||||||
|
@ -227,39 +258,47 @@ load(void *ctx, graph_builder_array *builder, graph_encoding encoding,
|
||||||
graph_builder xml = builder->buf[0];
|
graph_builder xml = builder->buf[0];
|
||||||
graph_builder weight = builder->buf[1];
|
graph_builder weight = builder->buf[1];
|
||||||
|
|
||||||
/* if xml is a String with a model in IR */
|
graph_idx = ov_ctx->n_graphs;
|
||||||
if (!(xml.buf[xml.size] == '\0' && xml.buf[xml.size - 1] != '\0')) {
|
if (graph_idx >= MAX_GRAPHS) {
|
||||||
NN_ERR_PRINTF("Invalid xml string.");
|
return runtime_error;
|
||||||
return invalid_argument;
|
|
||||||
}
|
}
|
||||||
|
graph = &ov_ctx->graphs[graph_idx];
|
||||||
|
memset(graph, 0, sizeof(*graph));
|
||||||
|
|
||||||
/* transfer weight to an ov tensor */
|
/* transfer weight to an ov tensor */
|
||||||
{
|
{
|
||||||
ov_ctx->weight_data = os_malloc(weight.size);
|
graph->weight_data = os_malloc(weight.size);
|
||||||
if (!ov_ctx->weight_data)
|
if (!graph->weight_data)
|
||||||
goto fail;
|
goto fail;
|
||||||
memcpy(ov_ctx->weight_data, weight.buf, weight.size);
|
memcpy(graph->weight_data, weight.buf, weight.size);
|
||||||
|
|
||||||
ov_element_type_e type = U8;
|
ov_element_type_e type = U8;
|
||||||
int64_t dims[1] = { weight.size };
|
int64_t dims[1] = { weight.size };
|
||||||
ov_shape_t shape = { 1, dims };
|
ov_shape_t shape = { 1, dims };
|
||||||
CHECK_OV_STATUS(ov_tensor_create_from_host_ptr(type, shape,
|
CHECK_OV_STATUS(ov_tensor_create_from_host_ptr(type, shape,
|
||||||
ov_ctx->weight_data,
|
graph->weight_data,
|
||||||
&ov_ctx->weights_tensor),
|
&graph->weights_tensor),
|
||||||
ret);
|
ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* load model from buffer */
|
/* load model from buffer */
|
||||||
CHECK_OV_STATUS(ov_core_read_model_from_memory_buffer(
|
CHECK_OV_STATUS(ov_core_read_model_from_memory_buffer(
|
||||||
ov_ctx->core, (char *)xml.buf, xml.size,
|
ov_ctx->core, (char *)xml.buf, xml.size,
|
||||||
ov_ctx->weights_tensor, &ov_ctx->model),
|
graph->weights_tensor, &graph->model),
|
||||||
ret);
|
ret);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
print_model_input_output_info(ov_ctx->model);
|
print_model_input_output_info(ov_ctx->model);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ret = success;
|
CHECK_OV_STATUS(ov_core_compile_model(ov_ctx->core, graph->model, "CPU", 0,
|
||||||
|
&graph->compiled_model),
|
||||||
|
ret);
|
||||||
|
|
||||||
|
*g = graph_idx;
|
||||||
|
ov_ctx->n_graphs++;
|
||||||
|
return success;
|
||||||
fail:
|
fail:
|
||||||
|
free_graph(graph);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,20 +306,62 @@ __attribute__((visibility("default"))) wasi_nn_error
|
||||||
load_by_name(void *ctx, const char *filename, uint32_t filename_len, graph *g)
|
load_by_name(void *ctx, const char *filename, uint32_t filename_len, graph *g)
|
||||||
{
|
{
|
||||||
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
||||||
|
struct OpenVINOGraph *graph;
|
||||||
|
unsigned int graph_idx;
|
||||||
wasi_nn_error ret = unsupported_operation;
|
wasi_nn_error ret = unsupported_operation;
|
||||||
|
|
||||||
CHECK_OV_STATUS(
|
graph_idx = ov_ctx->n_graphs;
|
||||||
ov_core_read_model(ov_ctx->core, filename, NULL, &ov_ctx->model), ret);
|
if (graph_idx >= MAX_GRAPHS) {
|
||||||
|
return runtime_error;
|
||||||
|
}
|
||||||
|
graph = &ov_ctx->graphs[graph_idx];
|
||||||
|
|
||||||
ret = success;
|
memset(graph, 0, sizeof(*graph));
|
||||||
|
CHECK_OV_STATUS(
|
||||||
|
ov_core_read_model(ov_ctx->core, filename, NULL, &graph->model), ret);
|
||||||
|
|
||||||
|
CHECK_OV_STATUS(ov_core_compile_model(ov_ctx->core, graph->model, "CPU", 0,
|
||||||
|
&graph->compiled_model),
|
||||||
|
ret);
|
||||||
|
|
||||||
|
*g = graph_idx;
|
||||||
|
ov_ctx->n_graphs++;
|
||||||
|
return success;
|
||||||
fail:
|
fail:
|
||||||
|
free_graph(graph);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((visibility("default"))) wasi_nn_error
|
__attribute__((visibility("default"))) wasi_nn_error
|
||||||
init_execution_context(void *ctx, graph g, graph_execution_context *exec_ctx)
|
init_execution_context(void *ctx, graph g, graph_execution_context *exec_ctx)
|
||||||
{
|
{
|
||||||
|
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
||||||
|
struct OpenVINOGraph *graph;
|
||||||
|
struct OpenVINOExecutionContext *exec;
|
||||||
|
unsigned int exec_idx;
|
||||||
|
wasi_nn_error ret;
|
||||||
|
|
||||||
|
if (g >= ov_ctx->n_graphs)
|
||||||
|
return runtime_error;
|
||||||
|
graph = &ov_ctx->graphs[g];
|
||||||
|
|
||||||
|
exec_idx = ov_ctx->n_execution_contexts;
|
||||||
|
if (exec_idx >= MAX_EXECUTION_CONTEXTS)
|
||||||
|
return runtime_error;
|
||||||
|
exec = &ov_ctx->execution_contexts[exec_idx];
|
||||||
|
|
||||||
|
memset(exec, 0, sizeof(*exec));
|
||||||
|
exec->graph = graph;
|
||||||
|
|
||||||
|
CHECK_OV_STATUS(ov_compiled_model_create_infer_request(
|
||||||
|
graph->compiled_model, &exec->infer_request),
|
||||||
|
ret);
|
||||||
|
|
||||||
|
*exec_ctx = exec_idx;
|
||||||
|
ov_ctx->n_execution_contexts++;
|
||||||
return success;
|
return success;
|
||||||
|
fail:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((visibility("default"))) wasi_nn_error
|
__attribute__((visibility("default"))) wasi_nn_error
|
||||||
|
@ -288,19 +369,15 @@ set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index,
|
||||||
tensor *wasi_nn_tensor)
|
tensor *wasi_nn_tensor)
|
||||||
{
|
{
|
||||||
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
||||||
|
struct OpenVINOExecutionContext *exec;
|
||||||
wasi_nn_error ret = unsupported_operation;
|
wasi_nn_error ret = unsupported_operation;
|
||||||
ov_shape_t input_shape = { 0 };
|
ov_shape_t input_shape = { 0 };
|
||||||
|
ov_tensor_t *input_tensor = NULL;
|
||||||
int64_t *ov_dims = NULL;
|
int64_t *ov_dims = NULL;
|
||||||
|
|
||||||
ov_preprocess_prepostprocessor_t *ppp = NULL;
|
if (exec_ctx >= ov_ctx->n_execution_contexts)
|
||||||
ov_preprocess_input_info_t *input_info = NULL;
|
return runtime_error;
|
||||||
ov_preprocess_input_tensor_info_t *input_tensor_info = NULL;
|
exec = &ov_ctx->execution_contexts[exec_ctx];
|
||||||
ov_layout_t *input_layout = NULL;
|
|
||||||
ov_preprocess_preprocess_steps_t *input_process = NULL;
|
|
||||||
ov_preprocess_input_model_info_t *p_input_model = NULL;
|
|
||||||
ov_layout_t *model_layout = NULL;
|
|
||||||
ov_preprocess_output_info_t *output_info = NULL;
|
|
||||||
ov_preprocess_output_tensor_info_t *output_tensor_info = NULL;
|
|
||||||
|
|
||||||
/* wasi_nn_tensor -> ov_tensor */
|
/* wasi_nn_tensor -> ov_tensor */
|
||||||
{
|
{
|
||||||
|
@ -310,17 +387,6 @@ set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index,
|
||||||
if (ret != success)
|
if (ret != success)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* NCHW -> NHWC */
|
|
||||||
if (wasi_nn_tensor->dimensions->size == 4 || ov_dims[1] == 3) {
|
|
||||||
/* N */
|
|
||||||
/* H */
|
|
||||||
ov_dims[1] = ov_dims[2];
|
|
||||||
/* W */
|
|
||||||
ov_dims[2] = ov_dims[3];
|
|
||||||
/* C */
|
|
||||||
ov_dims[3] = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_OV_STATUS(ov_shape_create(wasi_nn_tensor->dimensions->size,
|
CHECK_OV_STATUS(ov_shape_create(wasi_nn_tensor->dimensions->size,
|
||||||
ov_dims, &input_shape),
|
ov_dims, &input_shape),
|
||||||
ret);
|
ret);
|
||||||
|
@ -337,100 +403,21 @@ set_input(void *ctx, graph_execution_context exec_ctx, uint32_t index,
|
||||||
|
|
||||||
CHECK_OV_STATUS(ov_tensor_create_from_host_ptr(input_type, input_shape,
|
CHECK_OV_STATUS(ov_tensor_create_from_host_ptr(input_type, input_shape,
|
||||||
wasi_nn_tensor->data,
|
wasi_nn_tensor->data,
|
||||||
&ov_ctx->input_tensor),
|
&input_tensor),
|
||||||
ret);
|
ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set preprocess based on wasi_nn_tensor */
|
|
||||||
{
|
|
||||||
CHECK_OV_STATUS(
|
|
||||||
ov_preprocess_prepostprocessor_create(ov_ctx->model, &ppp), ret);
|
|
||||||
|
|
||||||
/* reuse user' created tensor's info */
|
|
||||||
CHECK_OV_STATUS(ov_preprocess_prepostprocessor_get_input_info_by_index(
|
|
||||||
ppp, index, &input_info),
|
|
||||||
ret);
|
|
||||||
CHECK_OV_STATUS(ov_preprocess_input_info_get_tensor_info(
|
|
||||||
input_info, &input_tensor_info),
|
|
||||||
ret);
|
|
||||||
CHECK_OV_STATUS(ov_preprocess_input_tensor_info_set_from(
|
|
||||||
input_tensor_info, ov_ctx->input_tensor),
|
|
||||||
ret);
|
|
||||||
/* ! HAS TO BE NHWC. Match previous layout conversion */
|
|
||||||
CHECK_OV_STATUS(ov_layout_create("NHWC", &input_layout), ret);
|
|
||||||
CHECK_OV_STATUS(ov_preprocess_input_tensor_info_set_layout(
|
|
||||||
input_tensor_info, input_layout),
|
|
||||||
ret);
|
|
||||||
|
|
||||||
/* add RESIZE */
|
|
||||||
CHECK_OV_STATUS(ov_preprocess_input_info_get_preprocess_steps(
|
|
||||||
input_info, &input_process),
|
|
||||||
ret);
|
|
||||||
CHECK_OV_STATUS(
|
|
||||||
ov_preprocess_preprocess_steps_resize(input_process, RESIZE_LINEAR),
|
|
||||||
ret);
|
|
||||||
|
|
||||||
/* input model */
|
|
||||||
CHECK_OV_STATUS(
|
|
||||||
ov_preprocess_input_info_get_model_info(input_info, &p_input_model),
|
|
||||||
ret);
|
|
||||||
// TODO: what if not?
|
|
||||||
CHECK_OV_STATUS(ov_layout_create("NCHW", &model_layout), ret);
|
|
||||||
CHECK_OV_STATUS(ov_preprocess_input_model_info_set_layout(p_input_model,
|
|
||||||
model_layout),
|
|
||||||
ret);
|
|
||||||
|
|
||||||
/* output -> F32(possibility) */
|
|
||||||
CHECK_OV_STATUS(ov_preprocess_prepostprocessor_get_output_info_by_index(
|
|
||||||
ppp, index, &output_info),
|
|
||||||
ret);
|
|
||||||
CHECK_OV_STATUS(ov_preprocess_output_info_get_tensor_info(
|
|
||||||
output_info, &output_tensor_info),
|
|
||||||
ret);
|
|
||||||
CHECK_OV_STATUS(
|
|
||||||
ov_preprocess_output_set_element_type(output_tensor_info, F32),
|
|
||||||
ret);
|
|
||||||
|
|
||||||
CHECK_OV_STATUS(
|
|
||||||
ov_preprocess_prepostprocessor_build(ppp, &ov_ctx->new_model), ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_OV_STATUS(ov_core_compile_model(ov_ctx->core, ov_ctx->new_model,
|
|
||||||
"CPU", 0, &ov_ctx->compiled_model),
|
|
||||||
ret);
|
|
||||||
|
|
||||||
CHECK_OV_STATUS(ov_compiled_model_create_infer_request(
|
|
||||||
ov_ctx->compiled_model, &ov_ctx->infer_request),
|
|
||||||
ret);
|
|
||||||
|
|
||||||
/* install ov_tensor -> infer_request */
|
/* install ov_tensor -> infer_request */
|
||||||
CHECK_OV_STATUS(ov_infer_request_set_input_tensor_by_index(
|
CHECK_OV_STATUS(ov_infer_request_set_input_tensor_by_index(
|
||||||
ov_ctx->infer_request, index, ov_ctx->input_tensor),
|
exec->infer_request, index, input_tensor),
|
||||||
ret);
|
ret);
|
||||||
ret = success;
|
ret = success;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (ov_dims)
|
if (ov_dims)
|
||||||
os_free(ov_dims);
|
os_free(ov_dims);
|
||||||
|
if (input_tensor)
|
||||||
|
ov_tensor_free(input_tensor);
|
||||||
ov_shape_free(&input_shape);
|
ov_shape_free(&input_shape);
|
||||||
if (ppp)
|
|
||||||
ov_preprocess_prepostprocessor_free(ppp);
|
|
||||||
if (input_info)
|
|
||||||
ov_preprocess_input_info_free(input_info);
|
|
||||||
if (input_tensor_info)
|
|
||||||
ov_preprocess_input_tensor_info_free(input_tensor_info);
|
|
||||||
if (input_layout)
|
|
||||||
ov_layout_free(input_layout);
|
|
||||||
if (input_process)
|
|
||||||
ov_preprocess_preprocess_steps_free(input_process);
|
|
||||||
if (p_input_model)
|
|
||||||
ov_preprocess_input_model_info_free(p_input_model);
|
|
||||||
if (model_layout)
|
|
||||||
ov_layout_free(model_layout);
|
|
||||||
if (output_info)
|
|
||||||
ov_preprocess_output_info_free(output_info);
|
|
||||||
if (output_tensor_info)
|
|
||||||
ov_preprocess_output_tensor_info_free(output_tensor_info);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -439,9 +426,14 @@ __attribute__((visibility("default"))) wasi_nn_error
|
||||||
compute(void *ctx, graph_execution_context exec_ctx)
|
compute(void *ctx, graph_execution_context exec_ctx)
|
||||||
{
|
{
|
||||||
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
||||||
|
struct OpenVINOExecutionContext *exec;
|
||||||
wasi_nn_error ret = unsupported_operation;
|
wasi_nn_error ret = unsupported_operation;
|
||||||
|
|
||||||
CHECK_OV_STATUS(ov_infer_request_infer(ov_ctx->infer_request), ret);
|
if (exec_ctx >= ov_ctx->n_execution_contexts)
|
||||||
|
return runtime_error;
|
||||||
|
exec = &ov_ctx->execution_contexts[exec_ctx];
|
||||||
|
|
||||||
|
CHECK_OV_STATUS(ov_infer_request_infer(exec->infer_request), ret);
|
||||||
ret = success;
|
ret = success;
|
||||||
fail:
|
fail:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -452,17 +444,27 @@ get_output(void *ctx, graph_execution_context exec_ctx, uint32_t index,
|
||||||
tensor_data output_tensor, uint32_t *output_tensor_size)
|
tensor_data output_tensor, uint32_t *output_tensor_size)
|
||||||
{
|
{
|
||||||
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
||||||
|
struct OpenVINOExecutionContext *exec;
|
||||||
wasi_nn_error ret = unsupported_operation;
|
wasi_nn_error ret = unsupported_operation;
|
||||||
ov_tensor_t *ov_tensor = NULL;
|
ov_tensor_t *ov_tensor = NULL;
|
||||||
void *data = NULL;
|
void *data = NULL;
|
||||||
size_t byte_size = 0;
|
size_t byte_size = 0;
|
||||||
|
|
||||||
|
if (exec_ctx >= ov_ctx->n_execution_contexts)
|
||||||
|
return runtime_error;
|
||||||
|
exec = &ov_ctx->execution_contexts[exec_ctx];
|
||||||
|
|
||||||
CHECK_OV_STATUS(ov_infer_request_get_output_tensor_by_index(
|
CHECK_OV_STATUS(ov_infer_request_get_output_tensor_by_index(
|
||||||
ov_ctx->infer_request, index, &ov_tensor),
|
exec->infer_request, index, &ov_tensor),
|
||||||
ret);
|
ret);
|
||||||
|
|
||||||
CHECK_OV_STATUS(ov_tensor_get_byte_size(ov_tensor, &byte_size), ret);
|
CHECK_OV_STATUS(ov_tensor_get_byte_size(ov_tensor, &byte_size), ret);
|
||||||
|
|
||||||
|
if (byte_size > *output_tensor_size) {
|
||||||
|
ret = too_large;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_OV_STATUS(ov_tensor_data(ov_tensor, &data), ret);
|
CHECK_OV_STATUS(ov_tensor_data(ov_tensor, &data), ret);
|
||||||
|
|
||||||
memcpy(output_tensor, data, byte_size);
|
memcpy(output_tensor, data, byte_size);
|
||||||
|
@ -511,7 +513,7 @@ init_backend(void **ctx)
|
||||||
*ctx = (void *)ov_ctx;
|
*ctx = (void *)ov_ctx;
|
||||||
return success;
|
return success;
|
||||||
fail:
|
fail:
|
||||||
openvino_destroy((void *)ov_ctx);
|
os_free(ov_ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,27 +521,16 @@ __attribute__((visibility("default"))) wasi_nn_error
|
||||||
deinit_backend(void *ctx)
|
deinit_backend(void *ctx)
|
||||||
{
|
{
|
||||||
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
OpenVINOContext *ov_ctx = (OpenVINOContext *)ctx;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
if (!ov_ctx)
|
if (!ov_ctx)
|
||||||
return invalid_argument;
|
return invalid_argument;
|
||||||
|
|
||||||
if (ov_ctx->weight_data)
|
for (i = 0; i < ov_ctx->n_execution_contexts; i++)
|
||||||
os_free(ov_ctx->weight_data);
|
free_execution_context(&ov_ctx->execution_contexts[i]);
|
||||||
|
|
||||||
if (ov_ctx->weights_tensor)
|
for (i = 0; i < ov_ctx->n_graphs; i++)
|
||||||
ov_tensor_free(ov_ctx->weights_tensor);
|
free_graph(&ov_ctx->graphs[i]);
|
||||||
|
|
||||||
if (ov_ctx->input_tensor)
|
|
||||||
ov_tensor_free(ov_ctx->input_tensor);
|
|
||||||
|
|
||||||
if (ov_ctx->infer_request)
|
|
||||||
ov_infer_request_free(ov_ctx->infer_request);
|
|
||||||
|
|
||||||
if (ov_ctx->compiled_model)
|
|
||||||
ov_compiled_model_free(ov_ctx->compiled_model);
|
|
||||||
|
|
||||||
if (ov_ctx->model)
|
|
||||||
ov_model_free(ov_ctx->model);
|
|
||||||
|
|
||||||
if (ov_ctx->core)
|
if (ov_ctx->core)
|
||||||
ov_core_free(ov_ctx->core);
|
ov_core_free(ov_ctx->core);
|
||||||
|
|
|
@ -9,10 +9,44 @@
|
||||||
#include "wasi_nn_types.h"
|
#include "wasi_nn_types.h"
|
||||||
#include "wasm_export.h"
|
#include "wasm_export.h"
|
||||||
|
|
||||||
|
#include "bh_platform.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
korp_mutex lock;
|
||||||
|
bool busy;
|
||||||
|
bool is_backend_ctx_initialized;
|
||||||
bool is_model_loaded;
|
bool is_model_loaded;
|
||||||
graph_encoding backend;
|
graph_encoding backend;
|
||||||
void *backend_ctx;
|
void *backend_ctx;
|
||||||
} WASINNContext;
|
} WASINNContext;
|
||||||
|
|
||||||
|
typedef wasi_nn_error (*LOAD)(void *, graph_builder_array *, graph_encoding,
|
||||||
|
execution_target, graph *);
|
||||||
|
typedef wasi_nn_error (*LOAD_BY_NAME)(void *, const char *, uint32_t, graph *);
|
||||||
|
typedef wasi_nn_error (*LOAD_BY_NAME_WITH_CONFIG)(void *, const char *,
|
||||||
|
uint32_t, void *, uint32_t,
|
||||||
|
graph *);
|
||||||
|
typedef wasi_nn_error (*INIT_EXECUTION_CONTEXT)(void *, graph,
|
||||||
|
graph_execution_context *);
|
||||||
|
typedef wasi_nn_error (*SET_INPUT)(void *, graph_execution_context, uint32_t,
|
||||||
|
tensor *);
|
||||||
|
typedef wasi_nn_error (*COMPUTE)(void *, graph_execution_context);
|
||||||
|
typedef wasi_nn_error (*GET_OUTPUT)(void *, graph_execution_context, uint32_t,
|
||||||
|
tensor_data, uint32_t *);
|
||||||
|
/* wasi-nn general APIs */
|
||||||
|
typedef wasi_nn_error (*BACKEND_INITIALIZE)(void **);
|
||||||
|
typedef wasi_nn_error (*BACKEND_DEINITIALIZE)(void *);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LOAD load;
|
||||||
|
LOAD_BY_NAME load_by_name;
|
||||||
|
LOAD_BY_NAME_WITH_CONFIG load_by_name_with_config;
|
||||||
|
INIT_EXECUTION_CONTEXT init_execution_context;
|
||||||
|
SET_INPUT set_input;
|
||||||
|
COMPUTE compute;
|
||||||
|
GET_OUTPUT get_output;
|
||||||
|
BACKEND_INITIALIZE init;
|
||||||
|
BACKEND_DEINITIALIZE deinit;
|
||||||
|
} api_function;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -85,12 +85,8 @@ is_valid_graph(TFLiteContext *tfl_ctx, graph g)
|
||||||
NN_ERR_PRINTF("Invalid graph: %d >= %d.", g, MAX_GRAPHS_PER_INST);
|
NN_ERR_PRINTF("Invalid graph: %d >= %d.", g, MAX_GRAPHS_PER_INST);
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
}
|
}
|
||||||
if (tfl_ctx->models[g].model_pointer == NULL) {
|
|
||||||
NN_ERR_PRINTF("Context (model) non-initialized.");
|
|
||||||
return runtime_error;
|
|
||||||
}
|
|
||||||
if (tfl_ctx->models[g].model == NULL) {
|
if (tfl_ctx->models[g].model == NULL) {
|
||||||
NN_ERR_PRINTF("Context (tflite model) non-initialized.");
|
NN_ERR_PRINTF("Context (model) non-initialized.");
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
|
@ -285,6 +281,11 @@ set_input(void *tflite_ctx, graph_execution_context ctx, uint32_t index,
|
||||||
{
|
{
|
||||||
TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx;
|
TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx;
|
||||||
|
|
||||||
|
if (input_tensor->type != fp32) {
|
||||||
|
NN_ERR_PRINTF("unsupported input tensor type %u", input_tensor->type);
|
||||||
|
return runtime_error;
|
||||||
|
}
|
||||||
|
|
||||||
wasi_nn_error res;
|
wasi_nn_error res;
|
||||||
if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx)))
|
if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx)))
|
||||||
return res;
|
return res;
|
||||||
|
@ -388,23 +389,34 @@ get_output(void *tflite_ctx, graph_execution_context ctx, uint32_t index,
|
||||||
return too_large;
|
return too_large;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t model_tensor_size = 1;
|
|
||||||
for (int i = 0; i < (int)tensor->dims->size; ++i)
|
|
||||||
model_tensor_size *= (uint32_t)tensor->dims->data[i];
|
|
||||||
|
|
||||||
if (*output_tensor_size < model_tensor_size) {
|
|
||||||
NN_ERR_PRINTF("Insufficient memory to copy tensor %d", index);
|
|
||||||
return too_large;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tensor->quantization.type == kTfLiteNoQuantization) {
|
if (tensor->quantization.type == kTfLiteNoQuantization) {
|
||||||
NN_DBG_PRINTF("No quantization information");
|
NN_DBG_PRINTF("No quantization information");
|
||||||
float *ot =
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
tfl_ctx->interpreters[ctx].interpreter->typed_output_tensor<float>(
|
if (*output_tensor_size < tensor->bytes) {
|
||||||
index);
|
NN_ERR_PRINTF("Insufficient memory to copy tensor %d", index);
|
||||||
|
return too_large;
|
||||||
int size = model_tensor_size * sizeof(float);
|
}
|
||||||
bh_memcpy_s(output_tensor, size, ot, size);
|
#else
|
||||||
|
/*
|
||||||
|
* for now, maintain the bug-to-bug compatibility with the old abi,
|
||||||
|
* where the size here is the number of fp32, not bytes.
|
||||||
|
*/
|
||||||
|
if (*output_tensor_size < tensor->bytes / sizeof(float)) {
|
||||||
|
NN_ERR_PRINTF("Insufficient memory to copy tensor %d", index);
|
||||||
|
return too_large;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
bh_memcpy_s(output_tensor, *output_tensor_size, tensor->data.data,
|
||||||
|
tensor->bytes);
|
||||||
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
|
*output_tensor_size = tensor->bytes;
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* for now, maintain the bug-to-bug compatibility with the old abi,
|
||||||
|
* where the size here is the number of fp32, not bytes.
|
||||||
|
*/
|
||||||
|
*output_tensor_size = tensor->bytes / sizeof(float);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else { // TODO: Assuming uint8 quantized networks.
|
else { // TODO: Assuming uint8 quantized networks.
|
||||||
TfLiteAffineQuantization *quant_info =
|
TfLiteAffineQuantization *quant_info =
|
||||||
|
@ -413,6 +425,27 @@ get_output(void *tflite_ctx, graph_execution_context ctx, uint32_t index,
|
||||||
NN_ERR_PRINTF("Quantization per channel is not supported");
|
NN_ERR_PRINTF("Quantization per channel is not supported");
|
||||||
return runtime_error;
|
return runtime_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t model_tensor_size = 1;
|
||||||
|
for (int i = 0; i < (int)tensor->dims->size; ++i)
|
||||||
|
model_tensor_size *= (uint32_t)tensor->dims->data[i];
|
||||||
|
|
||||||
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
|
if (*output_tensor_size / sizeof(float) < model_tensor_size) {
|
||||||
|
NN_ERR_PRINTF("Insufficient memory to copy tensor %d", index);
|
||||||
|
return too_large;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* for now, maintain the bug-to-bug compatibility with the old abi,
|
||||||
|
* where the size here is the number of fp32, not bytes.
|
||||||
|
*/
|
||||||
|
if (*output_tensor_size < model_tensor_size) {
|
||||||
|
NN_ERR_PRINTF("Insufficient memory to copy tensor %d", index);
|
||||||
|
return too_large;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t *ot = tfl_ctx->interpreters[ctx]
|
uint8_t *ot = tfl_ctx->interpreters[ctx]
|
||||||
.interpreter->typed_output_tensor<uint8_t>(index);
|
.interpreter->typed_output_tensor<uint8_t>(index);
|
||||||
|
|
||||||
|
@ -425,9 +458,18 @@ get_output(void *tflite_ctx, graph_execution_context ctx, uint32_t index,
|
||||||
for (uint32_t i = 0; i < model_tensor_size; ++i) {
|
for (uint32_t i = 0; i < model_tensor_size; ++i) {
|
||||||
output_tensor_f[i] = (ot[i] - zero_point) * scale;
|
output_tensor_f[i] = (ot[i] - zero_point) * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if WASM_ENABLE_WASI_EPHEMERAL_NN != 0
|
||||||
|
*output_tensor_size = model_tensor_size * sizeof(float);
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* for now, maintain the bug-to-bug compatibility with the old abi,
|
||||||
|
* where the size here is the number of fp32, not bytes.
|
||||||
|
*/
|
||||||
|
*output_tensor_size = model_tensor_size;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
*output_tensor_size = model_tensor_size;
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,32 +514,31 @@ deinit_backend(void *tflite_ctx)
|
||||||
NN_DBG_PRINTF("Freeing memory.");
|
NN_DBG_PRINTF("Freeing memory.");
|
||||||
for (int i = 0; i < MAX_GRAPHS_PER_INST; ++i) {
|
for (int i = 0; i < MAX_GRAPHS_PER_INST; ++i) {
|
||||||
tfl_ctx->models[i].model.reset();
|
tfl_ctx->models[i].model.reset();
|
||||||
if (tfl_ctx->models[i].model_pointer) {
|
if (tfl_ctx->delegate) {
|
||||||
if (tfl_ctx->delegate) {
|
switch (tfl_ctx->models[i].target) {
|
||||||
switch (tfl_ctx->models[i].target) {
|
case gpu:
|
||||||
case gpu:
|
{
|
||||||
{
|
|
||||||
#if WASM_ENABLE_WASI_NN_GPU != 0
|
#if WASM_ENABLE_WASI_NN_GPU != 0
|
||||||
TfLiteGpuDelegateV2Delete(tfl_ctx->delegate);
|
TfLiteGpuDelegateV2Delete(tfl_ctx->delegate);
|
||||||
#else
|
#else
|
||||||
NN_ERR_PRINTF("GPU delegate delete but not enabled.");
|
NN_ERR_PRINTF("GPU delegate delete but not enabled.");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case tpu:
|
|
||||||
{
|
|
||||||
#if WASM_ENABLE_WASI_NN_EXTERNAL_DELEGATE != 0
|
|
||||||
TfLiteExternalDelegateDelete(tfl_ctx->delegate);
|
|
||||||
#else
|
|
||||||
NN_ERR_PRINTF(
|
|
||||||
"External delegate delete but not enabled.");
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
case tpu:
|
||||||
|
{
|
||||||
|
#if WASM_ENABLE_WASI_NN_EXTERNAL_DELEGATE != 0
|
||||||
|
TfLiteExternalDelegateDelete(tfl_ctx->delegate);
|
||||||
|
#else
|
||||||
|
NN_ERR_PRINTF("External delegate delete but not enabled.");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (tfl_ctx->models[i].model_pointer) {
|
||||||
wasm_runtime_free(tfl_ctx->models[i].model_pointer);
|
wasm_runtime_free(tfl_ctx->models[i].model_pointer);
|
||||||
}
|
}
|
||||||
tfl_ctx->models[i].model_pointer = NULL;
|
tfl_ctx->models[i].model_pointer = NULL;
|
||||||
|
|
|
@ -3,6 +3,17 @@
|
||||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
# on intel mac, this ends up with a lot of the following error.
|
||||||
|
#
|
||||||
|
# AttributeError: 'Sequential' object has no attribute '_get_save_spec'.
|
||||||
|
#
|
||||||
|
# * "pip install tensorflow" installs tensorflow 2.16.2 on intel mac.
|
||||||
|
# (because it's the last version before tf deprecated the target.)
|
||||||
|
# * keras 3 support in the version seems incomplete (thus the error)
|
||||||
|
# * a workaround: use keras 2 as mentioned in:
|
||||||
|
# https://github.com/tensorflow/tensorflow/releases/tag/v2.16.1
|
||||||
|
# https://blog.tensorflow.org/2024/03/whats-new-in-tensorflow-216.html
|
||||||
|
|
||||||
CURR_PATH=$(cd $(dirname $0) && pwd -P)
|
CURR_PATH=$(cd $(dirname $0) && pwd -P)
|
||||||
|
|
||||||
# WASM application that uses WASI-NN
|
# WASM application that uses WASI-NN
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import tensorflow as tf
|
import tensorflow as tf
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from keras.layers import AveragePooling2D, Conv2D
|
from tensorflow.keras.layers import AveragePooling2D, Conv2D
|
||||||
|
|
||||||
from tensorflow.keras import Input, Model
|
from tensorflow.keras import Input, Model
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ wasm_load(char *model_name, graph *g, execution_target target)
|
||||||
wasi_nn_error
|
wasi_nn_error
|
||||||
wasm_load_by_name(const char *model_name, graph *g)
|
wasm_load_by_name(const char *model_name, graph *g)
|
||||||
{
|
{
|
||||||
wasi_nn_error res = load_by_name(model_name, g);
|
wasi_nn_error res = load_by_name(model_name, strlen(model_name), g);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,8 @@ run_inference(execution_target target, float *input, uint32_t *input_size,
|
||||||
uint32_t num_output_tensors)
|
uint32_t num_output_tensors)
|
||||||
{
|
{
|
||||||
graph graph;
|
graph graph;
|
||||||
if (wasm_load(model_name, &graph, target) != success) {
|
|
||||||
|
if (wasm_load_by_name(model_name, &graph) != success) {
|
||||||
NN_ERR_PRINTF("Error when loading model.");
|
NN_ERR_PRINTF("Error when loading model.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,10 +201,20 @@ openat(int fd, const char *pathname, int flags, ...)
|
||||||
int ret;
|
int ret;
|
||||||
char dir_path[DIR_PATH_LEN];
|
char dir_path[DIR_PATH_LEN];
|
||||||
char *full_path;
|
char *full_path;
|
||||||
|
mode_t mode = 0;
|
||||||
|
bool has_mode = false;
|
||||||
|
|
||||||
|
if (flags & O_CREAT) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, flags);
|
||||||
|
mode = (mode_t)va_arg(ap, int);
|
||||||
|
va_end(ap);
|
||||||
|
has_mode = true;
|
||||||
|
}
|
||||||
|
|
||||||
ret = fcntl(fd, F_GETPATH, dir_path);
|
ret = fcntl(fd, F_GETPATH, dir_path);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
errno = -EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +224,7 @@ openat(int fd, const char *pathname, int flags, ...)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_fd = open(full_path, flags);
|
new_fd = has_mode ? open(full_path, flags, mode) : open(full_path, flags);
|
||||||
free(full_path);
|
free(full_path);
|
||||||
|
|
||||||
return new_fd;
|
return new_fd;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
#define WAMR_VERSION_MAJOR 2
|
#define WAMR_VERSION_MAJOR 2
|
||||||
#define WAMR_VERSION_MINOR 3
|
#define WAMR_VERSION_MINOR 3
|
||||||
#define WAMR_VERSION_PATCH 0
|
#define WAMR_VERSION_PATCH 1
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -102,6 +102,7 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
|
||||||
|
|
||||||
### **Enable lib wasi-nn**
|
### **Enable lib wasi-nn**
|
||||||
- **WAMR_BUILD_WASI_NN**=1/0, default to disable if not set
|
- **WAMR_BUILD_WASI_NN**=1/0, default to disable if not set
|
||||||
|
> Note: WAMR_BUILD_WASI_NN without WAMR_BUILD_WASI_EPHEMERAL_NN is deprecated and will likely be removed in future versions of WAMR. Please consider to enable WAMR_BUILD_WASI_EPHEMERAL_NN as well.
|
||||||
> Note: See [WASI-NN](../core/iwasm/libraries/wasi-nn) for more details.
|
> Note: See [WASI-NN](../core/iwasm/libraries/wasi-nn) for more details.
|
||||||
|
|
||||||
### **Enable lib wasi-nn GPU mode**
|
### **Enable lib wasi-nn GPU mode**
|
||||||
|
@ -113,7 +114,7 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
|
||||||
- **WAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH**=Path to the external delegate shared library (e.g. `libedgetpu.so.1.0` for Coral USB)
|
- **WAMR_BUILD_WASI_NN_EXTERNAL_DELEGATE_PATH**=Path to the external delegate shared library (e.g. `libedgetpu.so.1.0` for Coral USB)
|
||||||
|
|
||||||
### **Enable lib wasi-nn with `wasi_ephemeral_nn` module support**
|
### **Enable lib wasi-nn with `wasi_ephemeral_nn` module support**
|
||||||
- **WAMR_BUILD_WASI_EPHEMERAL_NN**=1/0, default to disable if not set
|
- **WAMR_BUILD_WASI_EPHEMERAL_NN**=1/0, default to enable if not set
|
||||||
|
|
||||||
### **Disable boundary check with hardware trap**
|
### **Disable boundary check with hardware trap**
|
||||||
- **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform
|
- **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform
|
||||||
|
|
|
@ -4,6 +4,6 @@ WebAssembly [reference-types](https://github.com/WebAssembly/reference-types) pr
|
||||||
|
|
||||||
WAMR has implemented the reference-types proposal. WAMR allows a native method to pass a host object to a WASM application as an `externref` parameter or receives a host object from a WASM application as an `externref` result. Internally, WAMR won't try to parse or dereference `externref`. It is an opaque type.
|
WAMR has implemented the reference-types proposal. WAMR allows a native method to pass a host object to a WASM application as an `externref` parameter or receives a host object from a WASM application as an `externref` result. Internally, WAMR won't try to parse or dereference `externref`. It is an opaque type.
|
||||||
|
|
||||||
The restriction of using `externref` in a native method is the host object has to be the value of a `unintptr_t` variable. In other words, it takes **8 bytes** on 64-bit machine and **4 bytes** on 32-bit machines. Please keep that in mind especially when calling `wasm_runtime_call_wasm`.
|
The restriction of using `externref` in a native method is the host object has to be the value of a `uintptr_t` variable. In other words, it takes **8 bytes** on 64-bit machine and **4 bytes** on 32-bit machines. Please keep that in mind especially when calling `wasm_runtime_call_wasm`.
|
||||||
|
|
||||||
Please ref to the [sample](../samples/ref-types) for more details.
|
Please ref to the [sample](../samples/ref-types) for more details.
|
||||||
|
|
|
@ -112,12 +112,12 @@ def wasm_vec_to_list(vec):
|
||||||
wasm_frame_vec_t,
|
wasm_frame_vec_t,
|
||||||
wasm_extern_vec_t,
|
wasm_extern_vec_t,
|
||||||
]
|
]
|
||||||
known_vec_pointer_type = [POINTER(type) for type in known_vec_type]
|
known_vec_pointer_type = [POINTER(vec_type) for vec_type in known_vec_type]
|
||||||
|
|
||||||
if any([isinstance(vec, type) for type in known_vec_pointer_type]):
|
if any([isinstance(vec, pointer_type) for pointer_type in known_vec_pointer_type]):
|
||||||
vec = dereference(vec)
|
vec = dereference(vec)
|
||||||
return [vec.data[i] for i in range(vec.num_elems)]
|
return [vec.data[i] for i in range(vec.num_elems)]
|
||||||
elif any([isinstance(vec, type) for type in known_vec_type]):
|
elif any([isinstance(vec, vec_type) for vec_type in known_vec_type]):
|
||||||
return [vec.data[i] for i in range(vec.num_elems)]
|
return [vec.data[i] for i in range(vec.num_elems)]
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("not a known vector type")
|
raise RuntimeError("not a known vector type")
|
||||||
|
@ -405,7 +405,7 @@ def __compare_wasm_val_t(self, other):
|
||||||
elif WASM_F32 == self.kind:
|
elif WASM_F32 == self.kind:
|
||||||
return self.of.f32 == other.of.f32
|
return self.of.f32 == other.of.f32
|
||||||
elif WASM_F64 == self.kind:
|
elif WASM_F64 == self.kind:
|
||||||
return self.of.f64 == other.of.f63
|
return self.of.f64 == other.of.f64
|
||||||
elif WASM_EXTERNREF == self.kind:
|
elif WASM_EXTERNREF == self.kind:
|
||||||
raise RuntimeError("FIXME")
|
raise RuntimeError("FIXME")
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
### Pre-requisites
|
### Pre-requisites
|
||||||
#### Install requirements
|
#### Install requirements
|
||||||
Before proceeding it is necessary to make sure your Python environment is correctly configured. To do ths open a terminal session in this directory and perfom the following:
|
Before proceeding it is necessary to make sure your Python environment is correctly configured. To do this open a terminal session in this directory and perform the following:
|
||||||
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|
|
@ -353,12 +353,12 @@ writable and needs to be copied into a ctype array.
|
||||||
|
|
||||||
#### variable arguments
|
#### variable arguments
|
||||||
|
|
||||||
A function with _variable arugments_ makes it hard to specify the required
|
A function with _variable arguments_ makes it hard to specify the required
|
||||||
argument types for the function prototype. It leaves us one way to call it
|
argument types for the function prototype. It leaves us one way to call it
|
||||||
directly without any arguments type checking.
|
directly without any arguments type checking.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
libc.printf(b"Hello, an int %d, a float %f, a string %s\n", c_int(1), c_doulbe(3.14), "World!")
|
libc.printf(b"Hello, an int %d, a float %f, a string %s\n", c_int(1), c_double(3.14), "World!")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Use `c_bool` to represent `wasm_mutability_t `
|
#### Use `c_bool` to represent `wasm_mutability_t `
|
||||||
|
@ -373,7 +373,7 @@ libc.printf(b"Hello, an int %d, a float %f, a string %s\n", c_int(1), c_doulbe(3
|
||||||
|
|
||||||
### bindgen.py
|
### bindgen.py
|
||||||
|
|
||||||
`bindge.py` is a tool to create WAMR python binding automatically. `binding.py`
|
`bindgen.py` is a tool to create WAMR python binding automatically. `binding.py`
|
||||||
is generated. We should avoid modification on it. Additional helpers should go
|
is generated. We should avoid modification on it. Additional helpers should go
|
||||||
to `ffi.py`.
|
to `ffi.py`.
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,12 @@ set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
|
|
||||||
set (CMAKE_MACOSX_RPATH True)
|
set (CMAKE_MACOSX_RPATH True)
|
||||||
|
|
||||||
|
# if enable wasi-nn, both wasi-nn-backends and iwasm
|
||||||
|
# need to use same WAMR (dynamic) libraries
|
||||||
|
if (WAMR_BUILD_WASI_NN EQUAL 1)
|
||||||
|
set (BUILD_SHARED_LIBS ON)
|
||||||
|
endif ()
|
||||||
|
|
||||||
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
||||||
|
|
||||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||||
|
|
|
@ -79,7 +79,7 @@ struct wamr_pal_create_process_args {
|
||||||
// Untrusted environment variable array pass to new process.
|
// Untrusted environment variable array pass to new process.
|
||||||
//
|
//
|
||||||
// The untrusted env vars to the command. And the last element of the array
|
// The untrusted env vars to the command. And the last element of the array
|
||||||
// must be NULL to indicate the length of array.
|
// must be NULL to indicate the end of the array.
|
||||||
//
|
//
|
||||||
// Optional field.
|
// Optional field.
|
||||||
const char **env;
|
const char **env;
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
# Refer to https://docs.zephyrproject.org/3.7.0/develop/getting_started/index.html
|
||||||
|
# for more information on how to set up the Zephyr development environment.
|
||||||
FROM ubuntu:22.04
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ENV TZ=Asian/Shanghai
|
ENV TZ=Asian/Shanghai
|
||||||
|
ARG ZEPHYR_SDK_VERSION=0.16.9
|
||||||
|
# In west_lite.yml, the Zephyr version is set to v3.7.0
|
||||||
|
#ARG ZEPHYR_VERSION=3.7.0
|
||||||
|
|
||||||
# Install dependencies for Zephyr
|
# Install dependencies for Zephyr
|
||||||
# hadolint ignore=DL3008
|
# hadolint ignore=DL3008
|
||||||
|
@ -16,28 +22,34 @@ RUN apt-get update && apt-get install -y --no-install-recommends git cmake ninja
|
||||||
# Install the Zephyr Software Development Kit (SDK)
|
# Install the Zephyr Software Development Kit (SDK)
|
||||||
WORKDIR /opt
|
WORKDIR /opt
|
||||||
# hadolint ignore=DL4006
|
# hadolint ignore=DL4006
|
||||||
RUN wget --progress=dot:giga https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz \
|
RUN wget --progress=dot:giga https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${ZEPHYR_SDK_VERSION}/zephyr-sdk-${ZEPHYR_SDK_VERSION}_linux-x86_64.tar.xz \
|
||||||
&& wget --progress=dot:giga -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing \
|
&& wget --progress=dot:giga -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${ZEPHYR_SDK_VERSION}/sha256.sum | shasum --check --ignore-missing \
|
||||||
&& tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz && rm zephyr-sdk-0.16.3_linux-x86_64.tar.xz
|
&& tar xf zephyr-sdk-${ZEPHYR_SDK_VERSION}_linux-x86_64.tar.xz && rm zephyr-sdk-${ZEPHYR_SDK_VERSION}_linux-x86_64.tar.xz
|
||||||
|
|
||||||
WORKDIR /opt/zephyr-sdk-0.16.3
|
WORKDIR /opt/zephyr-sdk-${ZEPHYR_SDK_VERSION}
|
||||||
# hadolint ignore=DL4006
|
# hadolint ignore=DL4006
|
||||||
RUN yes | ./setup.sh
|
# Install host tools and Register Zephyr SDK CMake package
|
||||||
|
RUN ./setup.sh -h -c
|
||||||
|
|
||||||
# Get Zephyr
|
# Get Zephyr
|
||||||
|
WORKDIR /root/zephyrproject/smoke-test
|
||||||
|
|
||||||
# hadolint ignore=DL3013
|
# hadolint ignore=DL3013
|
||||||
RUN pip3 install --no-cache-dir west && west init -m https://github.com/zephyrproject-rtos/zephyr --mr v3.5.0 /root/zephyrproject
|
RUN pip3 install --no-cache-dir west
|
||||||
|
COPY ./west_lite.yml ./west.yml
|
||||||
|
|
||||||
|
# init the west workspace with a minimal manifest
|
||||||
|
RUN west init -l
|
||||||
|
|
||||||
WORKDIR /root/zephyrproject
|
WORKDIR /root/zephyrproject
|
||||||
RUN west update
|
RUN west update --stats
|
||||||
|
|
||||||
WORKDIR /root/zephyrproject/zephyr
|
WORKDIR /root/zephyrproject/modules/zephyr
|
||||||
RUN west zephyr-export && pip install --no-cache-dir -r ~/zephyrproject/zephyr/scripts/requirements.txt
|
RUN west zephyr-export && pip install --no-cache-dir -r ./scripts/requirements.txt
|
||||||
|
|
||||||
|
ENV ZEPHYR_BASE="/root/zephyrproject/modules/zephyr"
|
||||||
|
|
||||||
# Git clone wamr
|
# Git clone wamr
|
||||||
WORKDIR /root
|
WORKDIR /root/zephyrproject/modules/
|
||||||
RUN git clone https://github.com/bytecodealliance/wasm-micro-runtime.git
|
RUN git clone https://github.com/bytecodealliance/wasm-micro-runtime.git wasm-micro-runtime
|
||||||
|
WORKDIR /root/zephyrproject/modules/wasm-micro-runtime/product-mini/platforms/zephyr
|
||||||
WORKDIR /root/wasm-micro-runtime/product-mini/platforms/zephyr/simple
|
|
||||||
|
|
||||||
ENV ZEPHYR_BASE="/root/zephyrproject/zephyr"
|
|
||||||
|
|
|
@ -87,6 +87,12 @@ is a 64-bit ARM target for emulating the Cortex-A53 platform.
|
||||||
west build . -b qemu_cortex_a53 -p always -- -DWAMR_BUILD_TARGET=AARCH64
|
west build . -b qemu_cortex_a53 -p always -- -DWAMR_BUILD_TARGET=AARCH64
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[ARC QEMU](https://docs.zephyrproject.org/latest/boards/qemu/arc/doc/index.html)
|
||||||
|
is a 32-bit ARC target for emulating the ARC platform.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
west build . -b qemu_arc/qemu_arc_em -p always -- -DWAMR_BUILD_TARGET=ARC
|
||||||
|
```
|
||||||
|
|
||||||
## Flashing or Running Image
|
## Flashing or Running Image
|
||||||
|
|
||||||
|
|
15
product-mini/platforms/zephyr/simple/west_lite.yml
Normal file
15
product-mini/platforms/zephyr/simple/west_lite.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# The west manifest file for WAMR on Zephyr smoke test.
|
||||||
|
#
|
||||||
|
manifest:
|
||||||
|
#
|
||||||
|
# Please add items below based on alphabetical order
|
||||||
|
projects:
|
||||||
|
- name: zephyr
|
||||||
|
url: https://github.com/zephyrproject-rtos/zephyr
|
||||||
|
revision: v3.7.0
|
||||||
|
clone-depth: 1
|
||||||
|
path: modules/zephyr
|
||||||
|
west-commands: scripts/west-commands.yml
|
||||||
|
|
||||||
|
self:
|
||||||
|
path: smoke-test
|
|
@ -121,7 +121,6 @@ def main():
|
||||||
print("\n================================")
|
print("\n================================")
|
||||||
print("Test address resolving")
|
print("Test address resolving")
|
||||||
cmd = "./iwasm --allow-resolve=*.com addr_resolve.wasm github.com"
|
cmd = "./iwasm --allow-resolve=*.com addr_resolve.wasm github.com"
|
||||||
cmd = "./multicast_server FF02:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2"
|
|
||||||
run_cmd(cmd, args.working_directory)
|
run_cmd(cmd, args.working_directory)
|
||||||
|
|
||||||
# wait for a second
|
# wait for a second
|
||||||
|
|
|
@ -8,6 +8,8 @@ Refer to the `README.md` under each folder for how to build and run the benchmar
|
||||||
|
|
||||||
## Install `llvm-profdata`
|
## Install `llvm-profdata`
|
||||||
|
|
||||||
|
> PS: the `llvm-profdata` vesion needs to be the same major version with llvm libraries used to build wamrc.
|
||||||
|
|
||||||
The tool `llvm-profdata` is used when running the `test_pgo.sh` script under the benchmark folder. There are two ways to install it:
|
The tool `llvm-profdata` is used when running the `test_pgo.sh` script under the benchmark folder. There are two ways to install it:
|
||||||
|
|
||||||
1. Refer to https://apt.llvm.org/, e.g. in Ubuntu 20.04, add lines below to /etc/apt/source.list
|
1. Refer to https://apt.llvm.org/, e.g. in Ubuntu 20.04, add lines below to /etc/apt/source.list
|
||||||
|
@ -18,19 +20,22 @@ deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main
|
||||||
# 15
|
# 15
|
||||||
deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main
|
deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main
|
||||||
deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main
|
deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main
|
||||||
|
# 18
|
||||||
|
deb http://apt.llvm.org/focal/ llvm-toolchain-focal-18 main
|
||||||
|
deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-18 main
|
||||||
```
|
```
|
||||||
|
|
||||||
Then run `sudo apt update`, `sudo apt install llvm`. And after installing:
|
Then run `sudo apt update`, `sudo apt install llvm`. And after installing:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /usr/bin
|
cd /usr/bin
|
||||||
sudo ln -s llvm-profdata-15 llvm-profdata
|
sudo ln -s llvm-profdata-18 llvm-profdata
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Build manually
|
2. Build manually
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone --depth 1 --branch release/15.x https://github.com/llvm/llvm-project.git
|
git clone --depth 1 --branch release/18.x https://github.com/llvm/llvm-project.git
|
||||||
cd llvm-project
|
cd llvm-project
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake ../llvm \
|
cmake ../llvm \
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
set -e
|
||||||
|
|
||||||
PLATFORM=$(uname -s | tr A-Z a-z)
|
PLATFORM=$(uname -s | tr A-Z a-z)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
set -e
|
||||||
|
|
||||||
PLATFORM=$(uname -s | tr A-Z a-z)
|
PLATFORM=$(uname -s | tr A-Z a-z)
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ class memory64_atomic_test_suite : public testing::TestWithParam<RunningMode>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destory_exec_env()
|
void destroy_exec_env()
|
||||||
{
|
{
|
||||||
wasm_runtime_destroy_exec_env(exec_env);
|
wasm_runtime_destroy_exec_env(exec_env);
|
||||||
wasm_runtime_deinstantiate(module_inst);
|
wasm_runtime_deinstantiate(module_inst);
|
||||||
|
@ -109,7 +109,7 @@ class memory64_atomic_test_suite : public testing::TestWithParam<RunningMode>
|
||||||
virtual void TearDown()
|
virtual void TearDown()
|
||||||
{
|
{
|
||||||
if (cleanup) {
|
if (cleanup) {
|
||||||
destory_exec_env();
|
destroy_exec_env();
|
||||||
wasm_runtime_destroy();
|
wasm_runtime_destroy();
|
||||||
cleanup = false;
|
cleanup = false;
|
||||||
}
|
}
|
||||||
|
@ -339,8 +339,8 @@ TEST_P(memory64_atomic_test_suite, atomic_opcodes_i64_rmw_cmpxchg)
|
||||||
PUT_I64_TO_ADDR(wasm_argv + 2, 0x100F0E0D0C0B0A09);
|
PUT_I64_TO_ADDR(wasm_argv + 2, 0x100F0E0D0C0B0A09);
|
||||||
// new
|
// new
|
||||||
PUT_I64_TO_ADDR(wasm_argv + 4, 0xdeadcafebeefdead);
|
PUT_I64_TO_ADDR(wasm_argv + 4, 0xdeadcafebeefdead);
|
||||||
ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_rmw_cmpxchg"],
|
ASSERT_TRUE(wasm_runtime_call_wasm(
|
||||||
6, wasm_argv));
|
exec_env, func_map["i64_atomic_rmw_cmpxchg"], 6, wasm_argv));
|
||||||
i64 = 0x100F0E0D0C0B0A09;
|
i64 = 0x100F0E0D0C0B0A09;
|
||||||
ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv));
|
ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv));
|
||||||
|
|
||||||
|
|
|
@ -361,39 +361,39 @@ function sightglass_test()
|
||||||
|
|
||||||
function setup_wabt()
|
function setup_wabt()
|
||||||
{
|
{
|
||||||
WABT_VERSION=1.0.37
|
# please sync with .github/actions/install-wasi-sdk-wabt/action.yml
|
||||||
|
case ${PLATFORM} in
|
||||||
|
cosmopolitan)
|
||||||
|
;;
|
||||||
|
linux)
|
||||||
|
WABT_URL=https://github.com/WebAssembly/wabt/releases/download/1.0.37/wabt-1.0.37-ubuntu-20.04.tar.gz
|
||||||
|
WABT_VERSION=1.0.37
|
||||||
|
;;
|
||||||
|
darwin)
|
||||||
|
WABT_URL=https://github.com/WebAssembly/wabt/releases/download/1.0.36/wabt-1.0.36-macos-12.tar.gz
|
||||||
|
WABT_VERSION=1.0.36
|
||||||
|
;;
|
||||||
|
windows)
|
||||||
|
WABT_URL=https://github.com/WebAssembly/wabt/releases/download/1.0.37/wabt-1.0.37-windows.tar.gz
|
||||||
|
WABT_VERSION=1.0.37
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "wabt platform for ${PLATFORM} in unknown"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ ${WABT_BINARY_RELEASE} == "YES" ]; then
|
if [ ${WABT_BINARY_RELEASE} == "YES" ]; then
|
||||||
echo "download a binary release and install"
|
echo "download a binary release and install"
|
||||||
local WAT2WASM=${WORK_DIR}/wabt/out/gcc/Release/wat2wasm
|
local WAT2WASM=${WORK_DIR}/wabt/out/gcc/Release/wat2wasm
|
||||||
if [ ! -f ${WAT2WASM} ]; then
|
if [ ! -f ${WAT2WASM} ]; then
|
||||||
case ${PLATFORM} in
|
pushd /tmp
|
||||||
cosmopolitan)
|
wget -O wabt-tar.gz --progress=dot:giga ${WABT_URL}
|
||||||
;;
|
tar xf wabt-tar.gz
|
||||||
linux)
|
popd
|
||||||
WABT_PLATFORM=ubuntu-20.04
|
|
||||||
;;
|
|
||||||
darwin)
|
|
||||||
WABT_PLATFORM=macos-12
|
|
||||||
;;
|
|
||||||
windows)
|
|
||||||
WABT_PLATFORM=windows
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "wabt platform for ${PLATFORM} in unknown"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
if [ ! -f /tmp/wabt-${WABT_VERSION}-${WABT_PLATFORM}.tar.gz ]; then
|
|
||||||
curl -L \
|
|
||||||
https://github.com/WebAssembly/wabt/releases/download/${WABT_VERSION}/wabt-${WABT_VERSION}-${WABT_PLATFORM}.tar.gz \
|
|
||||||
-o /tmp/wabt-${WABT_VERSION}-${WABT_PLATFORM}.tar.gz
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd /tmp \
|
mkdir -p ${WORK_DIR}/wabt/out/gcc/Release/
|
||||||
&& tar zxf wabt-${WABT_VERSION}-${WABT_PLATFORM}.tar.gz \
|
cp /tmp/wabt-${WABT_VERSION}/bin/* ${WORK_DIR}/wabt/out/gcc/Release/
|
||||||
&& mkdir -p ${WORK_DIR}/wabt/out/gcc/Release/ \
|
|
||||||
&& install wabt-${WABT_VERSION}/bin/* ${WORK_DIR}/wabt/out/gcc/Release/ \
|
|
||||||
&& cd -
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "download source code and compile and install"
|
echo "download source code and compile and install"
|
||||||
|
@ -536,6 +536,9 @@ function spec_test()
|
||||||
popd
|
popd
|
||||||
echo $(pwd)
|
echo $(pwd)
|
||||||
|
|
||||||
|
#TODO: remove it when we can assume wabt is installed
|
||||||
|
# especially for CI Or there is installation script in the project
|
||||||
|
# that we can rely on
|
||||||
setup_wabt
|
setup_wabt
|
||||||
|
|
||||||
ln -sf ${WORK_DIR}/../spec-test-script/all.py .
|
ln -sf ${WORK_DIR}/../spec-test-script/all.py .
|
||||||
|
@ -622,8 +625,8 @@ function spec_test()
|
||||||
function wamr_compiler_test()
|
function wamr_compiler_test()
|
||||||
{
|
{
|
||||||
if [[ $1 != "aot" ]]; then
|
if [[ $1 != "aot" ]]; then
|
||||||
echo "WAMR compiler tests only support AOT mode"
|
echo "WAMR compiler tests only support AOT mode, skip $1"
|
||||||
exit 1
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Now start WAMR compiler tests"
|
echo "Now start WAMR compiler tests"
|
||||||
|
@ -877,51 +880,12 @@ function do_execute_in_running_mode()
|
||||||
{
|
{
|
||||||
local RUNNING_MODE="$1"
|
local RUNNING_MODE="$1"
|
||||||
|
|
||||||
if [[ ${ENABLE_MULTI_MEMORY} -eq 1 ]]; then
|
# filter out uncompatible running mode based on targeting proposal features
|
||||||
if [[ "${RUNNING_MODE}" != "classic-interp" \
|
# keep alpha order
|
||||||
&& "${RUNNING_MODE}" != "aot" ]]; then
|
|
||||||
echo "support multi-memory in classic-interp mode and aot mode"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${ENABLE_MEMORY64} -eq 1 ]]; then
|
if [[ ${ENABLE_EH} -eq 1 ]]; then
|
||||||
if [[ "${RUNNING_MODE}" != "classic-interp" \
|
if [[ "${RUNNING_MODE}" != "classic-interp" ]]; then
|
||||||
&& "${RUNNING_MODE}" != "aot" ]]; then
|
echo "support exception handling in classic-interp"
|
||||||
echo "support memory64(wasm64) in classic-interp mode and aot mode"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${ENABLE_MULTI_MODULE} -eq 1 ]]; then
|
|
||||||
if [[ "${RUNNING_MODE}" != "classic-interp" \
|
|
||||||
&& "${RUNNING_MODE}" != "fast-interp" \
|
|
||||||
&& "${RUNNING_MODE}" != "aot" ]]; then
|
|
||||||
echo "support multi-module in both interp modes"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${SGX_OPT} == "--sgx" ]]; then
|
|
||||||
if [[ "${RUNNING_MODE}" != "classic-interp" \
|
|
||||||
&& "${RUNNING_MODE}" != "fast-interp" \
|
|
||||||
&& "${RUNNING_MODE}" != "aot" \
|
|
||||||
&& "${RUNNING_MODE}" != "fast-jit" ]]; then
|
|
||||||
echo "support sgx in both interp modes, fast-jit mode and aot mode"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${ENABLE_SIMD} -eq 1 ]]; then
|
|
||||||
if [[ "${RUNNING_MODE}" != "jit" && "${RUNNING_MODE}" != "aot" && "${RUNNING_MODE}" != "fast-interp" ]]; then
|
|
||||||
echo "support simd in llvm-jit, aot and fast-interp mode"
|
|
||||||
return 0;
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${TARGET} == "X86_32" ]]; then
|
|
||||||
if [[ "${RUNNING_MODE}" == "jit" || "${RUNNING_MODE}" == "fast-jit" ]]; then
|
|
||||||
echo "both llvm-jit mode and fast-jit mode do not support X86_32 target"
|
|
||||||
return 0;
|
return 0;
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -936,9 +900,67 @@ function do_execute_in_running_mode()
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${ENABLE_EH} -eq 1 ]]; then
|
if [[ ${ENABLE_MEMORY64} -eq 1 ]]; then
|
||||||
|
if [[ "${RUNNING_MODE}" != "classic-interp" \
|
||||||
|
&& "${RUNNING_MODE}" != "aot" ]]; then
|
||||||
|
echo "support memory64(wasm64) in classic-interp mode and aot mode"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${ENABLE_MULTI_MEMORY} -eq 1 ]]; then
|
||||||
if [[ "${RUNNING_MODE}" != "classic-interp" ]]; then
|
if [[ "${RUNNING_MODE}" != "classic-interp" ]]; then
|
||||||
echo "support exception handling in classic-interp"
|
echo "support multi-memory in classic-interp mode mode"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${ENABLE_MULTI_MODULE} -eq 1 ]]; then
|
||||||
|
if [[ "${RUNNING_MODE}" != "classic-interp" \
|
||||||
|
&& "${RUNNING_MODE}" != "fast-interp" \
|
||||||
|
&& "${RUNNING_MODE}" != "aot" ]]; then
|
||||||
|
echo "support multi-module in both interp modes"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${ENABLE_SIMD} -eq 1 ]]; then
|
||||||
|
if [[ "${RUNNING_MODE}" != "jit" && "${RUNNING_MODE}" != "aot" && "${RUNNING_MODE}" != "fast-interp" ]]; then
|
||||||
|
echo "support simd in llvm-jit, aot and fast-interp mode"
|
||||||
|
return 0;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# filter out uncompatible running mode based on SGX support
|
||||||
|
if [[ ${SGX_OPT} == "--sgx" ]]; then
|
||||||
|
if [[ "${RUNNING_MODE}" != "classic-interp" \
|
||||||
|
&& "${RUNNING_MODE}" != "fast-interp" \
|
||||||
|
&& "${RUNNING_MODE}" != "aot" \
|
||||||
|
&& "${RUNNING_MODE}" != "fast-jit" ]]; then
|
||||||
|
echo "support sgx in both interp modes, fast-jit mode and aot mode"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# filter out uncompatible running mode based on architecture
|
||||||
|
if [[ ${TARGET} == "X86_32" ]]; then
|
||||||
|
if [[ "${RUNNING_MODE}" == "jit" || "${RUNNING_MODE}" == "fast-jit" || "${RUNNING_MODE}" == "multi-tier-jit" ]]; then
|
||||||
|
echo "both llvm-jit, fast-jit and multi-tier-jit mode do not support X86_32 target"
|
||||||
|
return 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${ENABLE_MEMORY64} -eq 1 ]]; then
|
||||||
|
echo "memory64 does not support X86_32 target"
|
||||||
|
return 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${ENABLE_MULTI_MEMORY} -eq 1 ]]; then
|
||||||
|
echo "multi-memory does not support X86_32 target"
|
||||||
|
return 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${ENABLE_SIMD} -eq 1 ]]; then
|
||||||
|
echo "simd does not support X86_32 target"
|
||||||
return 0;
|
return 0;
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -18,6 +18,7 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows")
|
||||||
else()
|
else()
|
||||||
project (aot-compiler C ASM CXX)
|
project (aot-compiler C ASM CXX)
|
||||||
enable_language (ASM_MASM)
|
enable_language (ASM_MASM)
|
||||||
|
add_definitions(-DCOMPILING_WASM_RUNTIME_API=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set (CMAKE_CXX_STANDARD 17)
|
set (CMAKE_CXX_STANDARD 17)
|
||||||
|
|
|
@ -137,9 +137,12 @@ print_help()
|
||||||
printf(" 3 - Small code model\n");
|
printf(" 3 - Small code model\n");
|
||||||
printf(" -sgx Generate code for SGX platform (Intel Software Guard Extensions)\n");
|
printf(" -sgx Generate code for SGX platform (Intel Software Guard Extensions)\n");
|
||||||
printf(" --bounds-checks=1/0 Enable or disable the bounds checks for memory access:\n");
|
printf(" --bounds-checks=1/0 Enable or disable the bounds checks for memory access:\n");
|
||||||
printf(" by default it is disabled in all 64-bit platforms except SGX and\n");
|
printf(" This flag controls bounds checking with a software check. \n");
|
||||||
printf(" in these platforms runtime does bounds checks with hardware trap,\n");
|
printf(" On 64-bit platforms, it is disabled by default, using a hardware \n");
|
||||||
printf(" and by default it is enabled in all 32-bit platforms\n");
|
printf(" trap if supported, except when SGX or memory64 is enabled,\n");
|
||||||
|
printf(" which defaults to a software check.\n");
|
||||||
|
printf(" On 32-bit platforms, the flag is enabled by default, using a software check\n");
|
||||||
|
printf(" due to the lack of hardware support.\n");
|
||||||
printf(" CAVEAT: --bounds-checks=0 enables some optimizations\n");
|
printf(" CAVEAT: --bounds-checks=0 enables some optimizations\n");
|
||||||
printf(" which make the compiled AOT module incompatible\n");
|
printf(" which make the compiled AOT module incompatible\n");
|
||||||
printf(" with a runtime without the hardware bounds checks.\n");
|
printf(" with a runtime without the hardware bounds checks.\n");
|
||||||
|
|
9
wamr-wasi-extensions/CMakeLists.txt
Normal file
9
wamr-wasi-extensions/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
cmake_minimum_required (VERSION 3.14)
|
||||||
|
|
||||||
|
project(wamr-wasi-extensions LANGUAGES C)
|
||||||
|
|
||||||
|
add_subdirectory(nn)
|
||||||
|
add_subdirectory(socket)
|
25
wamr-wasi-extensions/nn/CMakeLists.txt
Normal file
25
wamr-wasi-extensions/nn/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
add_library(wamr-wasi-nn INTERFACE)
|
||||||
|
|
||||||
|
set(wasi_nn_header_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../core/iwasm/libraries/wasi-nn/include)
|
||||||
|
|
||||||
|
set(headers
|
||||||
|
${wasi_nn_header_dir}/wasi_ephemeral_nn.h
|
||||||
|
${wasi_nn_header_dir}/wasi_nn.h
|
||||||
|
${wasi_nn_header_dir}/wasi_nn_types.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(TARGET wamr-wasi-nn PROPERTY PUBLIC_HEADER ${headers})
|
||||||
|
|
||||||
|
target_include_directories(wamr-wasi-nn
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${wasi_nn_header_dir}>
|
||||||
|
$<INSTALL_INTERFACE:include>)
|
||||||
|
|
||||||
|
install(TARGETS wamr-wasi-nn
|
||||||
|
EXPORT wamr-wasi-nn-config
|
||||||
|
PUBLIC_HEADER DESTINATION include/wamr)
|
||||||
|
install(EXPORT wamr-wasi-nn-config
|
||||||
|
DESTINATION lib/cmake/wamr-wasi-nn)
|
12
wamr-wasi-extensions/samples/nn-cli/CMakeLists.txt
Normal file
12
wamr-wasi-extensions/samples/nn-cli/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED YES)
|
||||||
|
|
||||||
|
project(nn-cli LANGUAGES C)
|
||||||
|
add_executable(nn-cli main.c fileio.c map.c)
|
||||||
|
find_package(wamr-wasi-nn REQUIRED)
|
||||||
|
target_link_libraries(nn-cli wamr-wasi-nn)
|
73
wamr-wasi-extensions/samples/nn-cli/fileio.c
Normal file
73
wamr-wasi-extensions/samples/nn-cli/fileio.c
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* modified copy-and-paste from:
|
||||||
|
* https://github.com/yamt/toywasm/blob/0eaad8cacd0cc7692946ff19b25994f106113be8/lib/fileio.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "fileio.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
map_file(const char *path, void **pp, size_t *sizep)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
size_t size;
|
||||||
|
ssize_t ssz;
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
ret = errno;
|
||||||
|
assert(ret != 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
struct stat st;
|
||||||
|
ret = fstat(fd, &st);
|
||||||
|
if (ret == -1) {
|
||||||
|
ret = errno;
|
||||||
|
assert(ret != 0);
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
size = st.st_size;
|
||||||
|
if (size > 0) {
|
||||||
|
p = malloc(size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Avoid a confusing error */
|
||||||
|
p = malloc(1);
|
||||||
|
}
|
||||||
|
if (p == NULL) {
|
||||||
|
close(fd);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
ssz = read(fd, p, size);
|
||||||
|
if (ssz != size) {
|
||||||
|
ret = errno;
|
||||||
|
assert(ret != 0);
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
*pp = p;
|
||||||
|
*sizep = size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unmap_file(void *p, size_t sz)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
14
wamr-wasi-extensions/samples/nn-cli/fileio.h
Normal file
14
wamr-wasi-extensions/samples/nn-cli/fileio.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* modified copy-and-paste from:
|
||||||
|
* https://github.com/yamt/toywasm/blob/0eaad8cacd0cc7692946ff19b25994f106113be8/lib/fileio.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
map_file(const char *filename, void **pp, size_t *szp);
|
||||||
|
void
|
||||||
|
unmap_file(void *p, size_t sz);
|
497
wamr-wasi-extensions/samples/nn-cli/main.c
Normal file
497
wamr-wasi-extensions/samples/nn-cli/main.c
Normal file
|
@ -0,0 +1,497 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <wamr/wasi_ephemeral_nn.h>
|
||||||
|
|
||||||
|
#include "fileio.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
static struct map graphs;
|
||||||
|
static struct map contexts;
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_graph(char *options)
|
||||||
|
{
|
||||||
|
int target = wasi_ephemeral_nn_target_cpu;
|
||||||
|
int encoding = wasi_ephemeral_nn_encoding_openvino;
|
||||||
|
const char *id = "default";
|
||||||
|
wasi_ephemeral_nn_graph_builder *builders = NULL;
|
||||||
|
size_t nbuilders = 0;
|
||||||
|
enum {
|
||||||
|
opt_id,
|
||||||
|
opt_file,
|
||||||
|
opt_encoding,
|
||||||
|
opt_target,
|
||||||
|
};
|
||||||
|
static char *const keylistp[] = {
|
||||||
|
[opt_id] = "id",
|
||||||
|
[opt_file] = "file",
|
||||||
|
[opt_encoding] = "encoding",
|
||||||
|
[opt_target] = "target",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
while (*options) {
|
||||||
|
extern char *suboptarg;
|
||||||
|
char *value;
|
||||||
|
const char *saved = options;
|
||||||
|
switch (getsubopt(&options, keylistp, &value)) {
|
||||||
|
case opt_id:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
id = value;
|
||||||
|
break;
|
||||||
|
case opt_file:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
builders =
|
||||||
|
realloc(builders, (nbuilders + 1) * sizeof(*builders));
|
||||||
|
if (builders == NULL) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
wasi_ephemeral_nn_graph_builder *b = &builders[nbuilders++];
|
||||||
|
int ret = map_file(value, (void *)&b->buf, (void *)&b->size);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "map_file \"%s\" failed: %s\n", value,
|
||||||
|
strerror(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case opt_encoding:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
encoding = atoi(value);
|
||||||
|
break;
|
||||||
|
case opt_target:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
target = atoi(value);
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
fprintf(stderr, "unknown subopt %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wasi_ephemeral_nn_error nnret;
|
||||||
|
wasi_ephemeral_nn_graph g;
|
||||||
|
nnret = wasi_ephemeral_nn_load(builders, nbuilders, encoding, target, &g);
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < nbuilders; i++) {
|
||||||
|
wasi_ephemeral_nn_graph_builder *b = &builders[i];
|
||||||
|
unmap_file(b->buf, b->size);
|
||||||
|
}
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "load failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
map_set(&graphs, id, g);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_execution_context(char *options)
|
||||||
|
{
|
||||||
|
const char *id = "default";
|
||||||
|
const char *graph_id = "default";
|
||||||
|
enum {
|
||||||
|
opt_id,
|
||||||
|
opt_graph_id,
|
||||||
|
};
|
||||||
|
static char *const keylistp[] = {
|
||||||
|
[opt_id] = "id",
|
||||||
|
[opt_graph_id] = "graph-id",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
while (*options) {
|
||||||
|
extern char *suboptarg;
|
||||||
|
char *value;
|
||||||
|
const char *saved = options;
|
||||||
|
switch (getsubopt(&options, keylistp, &value)) {
|
||||||
|
case opt_id:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
id = value;
|
||||||
|
break;
|
||||||
|
case opt_graph_id:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
graph_id = value;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
fprintf(stderr, "unknown subopt %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wasi_ephemeral_nn_graph g = map_get(&graphs, graph_id);
|
||||||
|
wasi_ephemeral_nn_graph_execution_context c;
|
||||||
|
wasi_ephemeral_nn_error nnret;
|
||||||
|
nnret = wasi_ephemeral_nn_init_execution_context(g, &c);
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "init_execution_context failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
map_set(&contexts, id, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_input(char *options)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const char *context_id = "default";
|
||||||
|
uint32_t idx = 0;
|
||||||
|
wasi_ephemeral_nn_tensor tensor = {
|
||||||
|
.dimensions = { .buf = NULL, .size = 0, },
|
||||||
|
.type = wasi_ephemeral_nn_type_fp32,
|
||||||
|
.data = NULL,
|
||||||
|
};
|
||||||
|
void *buf = NULL;
|
||||||
|
size_t sz = 0;
|
||||||
|
enum {
|
||||||
|
opt_context_id,
|
||||||
|
opt_dim,
|
||||||
|
opt_type,
|
||||||
|
opt_idx,
|
||||||
|
opt_file,
|
||||||
|
};
|
||||||
|
static char *const keylistp[] = {
|
||||||
|
[opt_context_id] = "context-id",
|
||||||
|
[opt_dim] = "dim",
|
||||||
|
[opt_type] = "type",
|
||||||
|
[opt_idx] = "idx",
|
||||||
|
[opt_file] = "file",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
while (*options) {
|
||||||
|
extern char *suboptarg;
|
||||||
|
char *value;
|
||||||
|
const char *saved = options;
|
||||||
|
switch (getsubopt(&options, keylistp, &value)) {
|
||||||
|
case opt_context_id:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
context_id = value;
|
||||||
|
break;
|
||||||
|
case opt_dim:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
wasi_ephemeral_nn_tensor_dimensions *dims = &tensor.dimensions;
|
||||||
|
|
||||||
|
dims->buf =
|
||||||
|
realloc(dims->buf, (dims->size + 1) * sizeof(*dims->buf));
|
||||||
|
if (dims->buf == NULL) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
dims->buf[dims->size++] = atoi(value);
|
||||||
|
break;
|
||||||
|
case opt_type:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
tensor.type = atoi(value);
|
||||||
|
break;
|
||||||
|
case opt_file:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
if (buf != NULL) {
|
||||||
|
fprintf(stderr, "duplicated tensor data\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
ret = map_file(value, &buf, &sz);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "map_file \"%s\" failed: %s\n", value,
|
||||||
|
strerror(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case opt_idx:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
idx = atoi(value);
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
fprintf(stderr, "unknown subopt %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tensor.dimensions.size == 0) {
|
||||||
|
fprintf(stderr, "no dimension is given\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
if (buf == NULL) {
|
||||||
|
fprintf(stderr, "no tensor is given\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* REVISIT: we can check the tensor size against type/dimensions
|
||||||
|
* and warn the user if unexpected.
|
||||||
|
*/
|
||||||
|
|
||||||
|
wasi_ephemeral_nn_error nnret;
|
||||||
|
wasi_ephemeral_nn_graph_execution_context c =
|
||||||
|
map_get(&contexts, context_id);
|
||||||
|
tensor.data.buf = buf;
|
||||||
|
tensor.data.size = sz;
|
||||||
|
nnret = wasi_ephemeral_nn_set_input(c, idx, &tensor);
|
||||||
|
unmap_file(buf, sz);
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "set_input failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
compute(char *options)
|
||||||
|
{
|
||||||
|
const char *context_id = "default";
|
||||||
|
enum {
|
||||||
|
opt_context_id,
|
||||||
|
};
|
||||||
|
static char *const keylistp[] = {
|
||||||
|
[opt_context_id] = "context-id",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
while (*options) {
|
||||||
|
extern char *suboptarg;
|
||||||
|
char *value;
|
||||||
|
const char *saved = options;
|
||||||
|
switch (getsubopt(&options, keylistp, &value)) {
|
||||||
|
case opt_context_id:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
context_id = value;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
fprintf(stderr, "unknown subopt %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wasi_ephemeral_nn_graph_execution_context c =
|
||||||
|
map_get(&contexts, context_id);
|
||||||
|
wasi_ephemeral_nn_error nnret;
|
||||||
|
nnret = wasi_ephemeral_nn_compute(c);
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "compute failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_output(char *options)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const char *outfile = NULL;
|
||||||
|
const char *context_id = "default";
|
||||||
|
uint32_t idx = 0;
|
||||||
|
enum {
|
||||||
|
opt_context_id,
|
||||||
|
opt_idx,
|
||||||
|
opt_file,
|
||||||
|
};
|
||||||
|
static char *const keylistp[] = {
|
||||||
|
[opt_context_id] = "context-id",
|
||||||
|
[opt_idx] = "idx",
|
||||||
|
[opt_file] = "file",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
while (*options) {
|
||||||
|
extern char *suboptarg;
|
||||||
|
char *value;
|
||||||
|
const char *saved = options;
|
||||||
|
switch (getsubopt(&options, keylistp, &value)) {
|
||||||
|
case opt_context_id:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
context_id = value;
|
||||||
|
break;
|
||||||
|
case opt_file:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
outfile = value;
|
||||||
|
break;
|
||||||
|
case opt_idx:
|
||||||
|
if (value == NULL) {
|
||||||
|
fprintf(stderr, "no value for %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
idx = atoi(value);
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
fprintf(stderr, "unknown subopt %s\n", saved);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int outfd = -1;
|
||||||
|
if (outfile != NULL) {
|
||||||
|
outfd = open(outfile, O_CREAT | O_TRUNC | O_WRONLY);
|
||||||
|
if (outfd == -1) {
|
||||||
|
fprintf(stderr, "failed to open output file \"%s\": %s\n", outfile,
|
||||||
|
strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wasi_ephemeral_nn_error nnret;
|
||||||
|
wasi_ephemeral_nn_graph_execution_context c =
|
||||||
|
map_get(&contexts, context_id);
|
||||||
|
void *resultbuf = NULL;
|
||||||
|
size_t resultbufsz = 256;
|
||||||
|
uint32_t resultsz;
|
||||||
|
retry:
|
||||||
|
resultbuf = realloc(resultbuf, resultbufsz);
|
||||||
|
if (resultbuf == NULL) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
nnret =
|
||||||
|
wasi_ephemeral_nn_get_output(c, 0, resultbuf, resultbufsz, &resultsz);
|
||||||
|
if (nnret == wasi_ephemeral_nn_error_too_large) {
|
||||||
|
resultbufsz *= 2;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "get_output failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (outfd != -1) {
|
||||||
|
ssize_t written = write(outfd, resultbuf, resultsz);
|
||||||
|
if (written == -1) {
|
||||||
|
fprintf(stderr, "failed to write: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (written == -1) {
|
||||||
|
fprintf(stderr, "unexpetecd write length %zu (expected %zu)\n",
|
||||||
|
written, (size_t)resultsz);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = close(outfd);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "failed to close: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "WARNING: discarding %zu bytes output\n",
|
||||||
|
(size_t)resultsz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum longopt {
|
||||||
|
opt_load_graph = 0x100,
|
||||||
|
opt_init_execution_context,
|
||||||
|
opt_set_input,
|
||||||
|
opt_compute,
|
||||||
|
opt_get_output,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct option longopts[] = {
|
||||||
|
{
|
||||||
|
"load-graph",
|
||||||
|
required_argument,
|
||||||
|
NULL,
|
||||||
|
opt_load_graph,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"init-execution-context",
|
||||||
|
optional_argument,
|
||||||
|
NULL,
|
||||||
|
opt_init_execution_context,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"set-input",
|
||||||
|
required_argument,
|
||||||
|
NULL,
|
||||||
|
opt_set_input,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"compute",
|
||||||
|
optional_argument,
|
||||||
|
NULL,
|
||||||
|
opt_compute,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"get-output",
|
||||||
|
optional_argument,
|
||||||
|
NULL,
|
||||||
|
opt_get_output,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
extern char *optarg;
|
||||||
|
int ch;
|
||||||
|
int longidx;
|
||||||
|
while ((ch = getopt_long(argc, argv, "", longopts, &longidx)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case opt_load_graph:
|
||||||
|
load_graph(optarg);
|
||||||
|
break;
|
||||||
|
case opt_init_execution_context:
|
||||||
|
init_execution_context(optarg ? optarg : "");
|
||||||
|
break;
|
||||||
|
case opt_set_input:
|
||||||
|
set_input(optarg);
|
||||||
|
break;
|
||||||
|
case opt_compute:
|
||||||
|
compute(optarg ? optarg : "");
|
||||||
|
break;
|
||||||
|
case opt_get_output:
|
||||||
|
get_output(optarg ? optarg : "");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
58
wamr-wasi-extensions/samples/nn-cli/map.c
Normal file
58
wamr-wasi-extensions/samples/nn-cli/map.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
static uintmax_t *
|
||||||
|
map_find_slot(struct map *m, const char *name)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < m->nentries; i++) {
|
||||||
|
if (!strcmp(m->entries[i].k, name)) {
|
||||||
|
return &m->entries[i].v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
map_append(struct map *m, const char *k, uintmax_t v)
|
||||||
|
{
|
||||||
|
m->entries = realloc(m->entries, (m->nentries + 1) * sizeof(*m->entries));
|
||||||
|
if (m->entries == NULL) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
struct map_entry *e = &m->entries[m->nentries++];
|
||||||
|
e->k = k;
|
||||||
|
e->v = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
map_set(struct map *m, const char *k, uintmax_t v)
|
||||||
|
{
|
||||||
|
uintmax_t *p = map_find_slot(m, k);
|
||||||
|
if (p != NULL) {
|
||||||
|
fprintf(stderr, "duplicated id \"%s\"\n", k);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
map_append(m, k, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintmax_t
|
||||||
|
map_get(struct map *m, const char *k)
|
||||||
|
{
|
||||||
|
uintmax_t *p = map_find_slot(m, k);
|
||||||
|
if (p == NULL) {
|
||||||
|
fprintf(stderr, "id \"%s\" not found\n", k);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return *p;
|
||||||
|
}
|
19
wamr-wasi-extensions/samples/nn-cli/map.h
Normal file
19
wamr-wasi-extensions/samples/nn-cli/map.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct map {
|
||||||
|
struct map_entry {
|
||||||
|
const char *k;
|
||||||
|
uintmax_t v;
|
||||||
|
} * entries;
|
||||||
|
size_t nentries;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
map_set(struct map *m, const char *k, uintmax_t v);
|
||||||
|
uintmax_t
|
||||||
|
map_get(struct map *m, const char *k);
|
13
wamr-wasi-extensions/samples/nn/CMakeLists.txt
Normal file
13
wamr-wasi-extensions/samples/nn/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED YES)
|
||||||
|
set(CMAKE_C_EXTENSIONS NO)
|
||||||
|
|
||||||
|
project(nn-classification-openvino LANGUAGES C)
|
||||||
|
add_executable(nn-classification-openvino "app.c")
|
||||||
|
find_package(wamr-wasi-nn REQUIRED)
|
||||||
|
target_link_libraries(nn-classification-openvino wamr-wasi-nn)
|
173
wamr-wasi-extensions/samples/nn/app.c
Normal file
173
wamr-wasi-extensions/samples/nn/app.c
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <wamr/wasi_ephemeral_nn.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* what this application does is basically same as:
|
||||||
|
* https://github.com/bytecodealliance/wasmtime/tree/efa236e58d09570baaf27865da33fb852fcf40a5/crates/wasi-nn/examples/classification-example
|
||||||
|
*
|
||||||
|
* map_file/unmap_file are copy-and-pasted from:
|
||||||
|
* https://github.com/yamt/toywasm/blob/0eaad8cacd0cc7692946ff19b25994f106113be8/lib/fileio.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
map_file(const char *path, void **pp, size_t *sizep)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
size_t size;
|
||||||
|
ssize_t ssz;
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
ret = errno;
|
||||||
|
assert(ret != 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
struct stat st;
|
||||||
|
ret = fstat(fd, &st);
|
||||||
|
if (ret == -1) {
|
||||||
|
ret = errno;
|
||||||
|
assert(ret != 0);
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
size = st.st_size;
|
||||||
|
if (size > 0) {
|
||||||
|
p = malloc(size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Avoid a confusing error */
|
||||||
|
p = malloc(1);
|
||||||
|
}
|
||||||
|
if (p == NULL) {
|
||||||
|
close(fd);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
ssz = read(fd, p, size);
|
||||||
|
if (ssz != size) {
|
||||||
|
ret = errno;
|
||||||
|
assert(ret != 0);
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
*pp = p;
|
||||||
|
*sizep = size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unmap_file(void *p, size_t sz)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_result(const float *result, size_t sz)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* just dump the raw result.
|
||||||
|
* you can postprocess the output with eg. "sort -k2nr | head"
|
||||||
|
*/
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < sz / sizeof(float); i++) {
|
||||||
|
printf("%d %f\n", i, result[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
wasi_ephemeral_nn_error nnret;
|
||||||
|
int ret;
|
||||||
|
void *xml;
|
||||||
|
size_t xmlsz;
|
||||||
|
ret = map_file("fixture/model.xml", &xml, &xmlsz);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "failed to load fixture/model.xml: %s\n",
|
||||||
|
strerror(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
void *weights;
|
||||||
|
size_t weightssz;
|
||||||
|
ret = map_file("fixture/model.bin", &weights, &weightssz);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "failed to load fixture/model.bin: %s\n",
|
||||||
|
strerror(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* note: openvino takes two buffers, namely IR and weights */
|
||||||
|
wasi_ephemeral_nn_graph_builder builders[2] = { {
|
||||||
|
.buf = xml,
|
||||||
|
.size = xmlsz,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.buf = weights,
|
||||||
|
.size = weightssz,
|
||||||
|
} };
|
||||||
|
wasi_ephemeral_nn_graph g;
|
||||||
|
nnret =
|
||||||
|
wasi_ephemeral_nn_load(builders, 2, wasi_ephemeral_nn_encoding_openvino,
|
||||||
|
wasi_ephemeral_nn_target_cpu, &g);
|
||||||
|
unmap_file(xml, xmlsz);
|
||||||
|
unmap_file(weights, weightssz);
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "load failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
wasi_ephemeral_nn_graph_execution_context ctx;
|
||||||
|
nnret = wasi_ephemeral_nn_init_execution_context(g, &ctx);
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "init_execution_context failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
void *tensordata;
|
||||||
|
size_t tensordatasz;
|
||||||
|
ret = map_file("fixture/tensor.bgr", &tensordata, &tensordatasz);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "failed to load fixture/tensor.bgr: %s\n",
|
||||||
|
strerror(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
wasi_ephemeral_nn_tensor tensor = {
|
||||||
|
.dimensions = { .buf = (uint32_t[]){1, 3, 224, 224,}, .size = 4, },
|
||||||
|
.type = wasi_ephemeral_nn_type_fp32,
|
||||||
|
.data.buf = tensordata,
|
||||||
|
.data.size = tensordatasz,
|
||||||
|
};
|
||||||
|
nnret = wasi_ephemeral_nn_set_input(ctx, 0, &tensor);
|
||||||
|
unmap_file(tensordata, tensordatasz);
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "set_input failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
nnret = wasi_ephemeral_nn_compute(ctx);
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "compute failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
float result[1001];
|
||||||
|
uint32_t resultsz;
|
||||||
|
nnret = wasi_ephemeral_nn_get_output(ctx, 0, (void *)result, sizeof(result),
|
||||||
|
&resultsz);
|
||||||
|
if (nnret != wasi_ephemeral_nn_error_success) {
|
||||||
|
fprintf(stderr, "get_output failed with %d\n", (int)nnret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
print_result(result, resultsz);
|
||||||
|
}
|
11
wamr-wasi-extensions/samples/socket-nslookup/CMakeLists.txt
Normal file
11
wamr-wasi-extensions/samples/socket-nslookup/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED YES)
|
||||||
|
set(CMAKE_C_EXTENSIONS NO)
|
||||||
|
|
||||||
|
project(socket-nslookup LANGUAGES C)
|
||||||
|
add_executable(socket-nslookup ${CMAKE_CURRENT_SOURCE_DIR}/../../../core/iwasm/libraries/lib-socket/test/nslookup.c)
|
||||||
|
find_package(wamr-wasi-socket REQUIRED)
|
||||||
|
target_link_libraries(socket-nslookup wamr-wasi-socket)
|
||||||
|
target_link_options(socket-nslookup PRIVATE -Wl,--max-memory=262144)
|
10
wamr-wasi-extensions/samples/socket-tcp-udp/CMakeLists.txt
Normal file
10
wamr-wasi-extensions/samples/socket-tcp-udp/CMakeLists.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED YES)
|
||||||
|
|
||||||
|
project(socket-tcp-udp LANGUAGES C)
|
||||||
|
add_executable(socket-tcp-udp ${CMAKE_CURRENT_SOURCE_DIR}/../../../core/iwasm/libraries/lib-socket/test/tcp_udp.c)
|
||||||
|
find_package(wamr-wasi-socket REQUIRED)
|
||||||
|
target_link_libraries(socket-tcp-udp wamr-wasi-socket)
|
||||||
|
target_link_options(socket-tcp-udp PRIVATE -Wl,--max-memory=262144)
|
26
wamr-wasi-extensions/socket/CMakeLists.txt
Normal file
26
wamr-wasi-extensions/socket/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
set(wasi_socket_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../core/iwasm/libraries/lib-socket)
|
||||||
|
set(wasi_socket_header_dir ${wasi_socket_dir}/inc)
|
||||||
|
|
||||||
|
set(srcs ${wasi_socket_dir}/src/wasi/wasi_socket_ext.c)
|
||||||
|
set(headers
|
||||||
|
${wasi_socket_header_dir}/wasi_socket_ext.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(wamr-wasi-socket STATIC ${srcs})
|
||||||
|
set_property(TARGET wamr-wasi-socket PROPERTY PUBLIC_HEADER ${headers})
|
||||||
|
target_include_directories(wamr-wasi-socket
|
||||||
|
PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${wasi_socket_header_dir}>
|
||||||
|
$<INSTALL_INTERFACE:include>)
|
||||||
|
|
||||||
|
# as this is a library, be extra conservative about wasm features
|
||||||
|
# to improve compatibilities. as this particular library is just a
|
||||||
|
# simple static stub, extra wasm features won't benefit us much anyway.
|
||||||
|
# note that LLVM-19 enables reference-types by default.
|
||||||
|
target_compile_options(wamr-wasi-socket PRIVATE -mno-reference-types)
|
||||||
|
|
||||||
|
install(TARGETS wamr-wasi-socket
|
||||||
|
EXPORT wamr-wasi-socket-config
|
||||||
|
PUBLIC_HEADER DESTINATION include)
|
||||||
|
install(EXPORT wamr-wasi-socket-config
|
||||||
|
DESTINATION lib/cmake/wamr-wasi-socket)
|
39
wamr-wasi-extensions/test.sh
Executable file
39
wamr-wasi-extensions/test.sh
Executable file
|
@ -0,0 +1,39 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
# Copyright (C) 2025 Midokura Japan KK. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PREFIX=/tmp/wamr
|
||||||
|
WASI_SDK=${WASI_SDK:-/opt/wasi-sdk}
|
||||||
|
|
||||||
|
cmake -B build-lib \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=${WASI_SDK}/share/cmake/wasi-sdk.cmake \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=${PREFIX} \
|
||||||
|
.
|
||||||
|
cmake --build build-lib -t install
|
||||||
|
|
||||||
|
cmake -B build-app-nn \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=${WASI_SDK}/share/cmake/wasi-sdk.cmake \
|
||||||
|
-DCMAKE_PREFIX_PATH=${PREFIX} \
|
||||||
|
samples/nn
|
||||||
|
cmake --build build-app-nn
|
||||||
|
|
||||||
|
cmake -B build-app-nn-cli \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=${WASI_SDK}/share/cmake/wasi-sdk.cmake \
|
||||||
|
-DCMAKE_PREFIX_PATH=${PREFIX} \
|
||||||
|
samples/nn-cli
|
||||||
|
cmake --build build-app-nn-cli
|
||||||
|
|
||||||
|
cmake -B build-app-socket-nslookup \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=${WASI_SDK}/share/cmake/wasi-sdk-pthread.cmake \
|
||||||
|
-DCMAKE_PREFIX_PATH=${PREFIX} \
|
||||||
|
samples/socket-nslookup
|
||||||
|
cmake --build build-app-socket-nslookup
|
||||||
|
|
||||||
|
cmake -B build-app-socket-tcp-udp \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=${WASI_SDK}/share/cmake/wasi-sdk-pthread.cmake \
|
||||||
|
-DCMAKE_PREFIX_PATH=${PREFIX} \
|
||||||
|
samples/socket-tcp-udp
|
||||||
|
cmake --build build-app-socket-tcp-udp
|
Loading…
Reference in New Issue
Block a user