Merge main into dev/fast_jit

This commit is contained in:
Wenyong Huang 2022-06-20 21:55:42 +08:00
commit 8ee2e0a22b
95 changed files with 9756 additions and 916 deletions

View File

@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cancel Workflow Action
uses: styfle/cancel-workflow-action@0.6.0
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0

View File

@ -1,7 +1,7 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
name: compilation on android, ubuntu-18.04, ubuntu-20.04, macos-latest
name: compilation on android, ubuntu-18.04, ubuntu-20.04
on:
# will be triggered on PR events
@ -11,7 +11,7 @@ on:
- "ci/**"
- "doc/**"
- "test-tools/**"
- ".github/workflows/compilation_on_android_ubuntu_macos.yml"
- ".github/workflows/compilation_on_android_ubuntu.yml"
# will be triggered on push events
push:
paths-ignore:
@ -19,7 +19,7 @@ on:
- "ci/**"
- "doc/**"
- "test-tools/**"
- ".github/workflows/compilation_on_android_ubuntu_macos.yml"
- ".github/workflows/compilation_on_android_ubuntu.yml"
# allow to be triggered manually
workflow_dispatch:
@ -30,12 +30,20 @@ concurrency:
cancel-in-progress: true
env:
# For BUILD
AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
# LLVM
LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
# For Spec Test
DEFAULT_TEST_OPTIONS: "-s spec -P"
MULTI_MODULES_TEST_OPTIONS: "-s spec -M -P"
SIMD_TEST_OPTIONS: "-s spec -S -P"
THREADS_TEST_OPTIONS: "-s spec -p -P"
X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
jobs:
# Cancel any in-flight jobs for the same PR/branch so there's only one active
@ -44,25 +52,25 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-20.04, macos-latest]
os: [ubuntu-18.04, ubuntu-20.04]
steps:
- name: Cancel Workflow Action
uses: styfle/cancel-workflow-action@0.6.0
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
# set different traffic lights based on the current repo and the running OS.
# according to light colors, the workflow will run different jobs
# it is used to separate between the public repo and the private repo
check_repo:
needs: cancel_previous
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-20.04, macos-latest]
os: [ubuntu-18.04, ubuntu-20.04]
outputs:
traffic_light_on_ubuntu_1804: ${{ steps.do_check_on_ubuntu_1804.outputs.light }}
traffic_light_on_ubuntu_2004: ${{ steps.do_check_on_ubuntu_2004.outputs.light }}
traffic_light_on_macos_latest: ${{ steps.do_check_on_macos_latest.outputs.light }}
steps:
- name: do_check_on_ubuntu_1804
id: do_check_on_ubuntu_1804
@ -84,41 +92,29 @@ jobs:
echo "::set-output name=light::green"
fi
- name: do_check_on_macos_latest
id: do_check_on_macos_latest
if: ${{ matrix.os == 'macos-latest' }}
run: |
if [[ ${{ github.repository }} == */wasm-micro-runtime ]]; then
echo "::set-output name=light::green"
else
echo "::set-output name=light::red"
fi
build_llvm_libraries:
needs: check_repo
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-20.04, macos-latest]
os: [ubuntu-18.04, ubuntu-20.04]
include:
- os: ubuntu-18.04
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_1804 }}
- os: ubuntu-20.04
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }}
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light_on_macos_latest }}
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Cache LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
./core/deps/llvm/build/bin
@ -128,43 +124,35 @@ jobs:
./core/deps/llvm/build/share
key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Build llvm and clang from source on ubuntu
id: build_llvm_ubuntu
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' && matrix.os != 'macos-latest' }}
- name: Build llvm and clang from source
id: build_llvm
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly --project clang lldb
working-directory: build-scripts
- name: Build llvm and clang from source on macos
id: build_llvm_macos
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' && matrix.os == 'macos-latest' }}
run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly
working-directory: build-scripts
build_wamrc:
needs: [build_llvm_libraries, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-20.04, macos-latest]
os: [ubuntu-18.04, ubuntu-20.04]
include:
- os: ubuntu-18.04
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_1804 }}
- os: ubuntu-20.04
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }}
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light_on_macos_latest }}
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Get LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
./core/deps/llvm/build/bin
@ -193,11 +181,11 @@ jobs:
matrix:
make_options_run_mode: [
# Running mode
$AOT_BUILD_OPTIONS,
$CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS,
$LAZY_JIT_BUILD_OPTIONS,
$MC_JIT_BUILD_OPTIONS,
$AOT_BUILD_OPTIONS,
]
make_options_feature: [
# Features
@ -206,6 +194,7 @@ jobs:
"-DWAMR_BUILD_DEBUG_INTERP=1",
"-DWAMR_BUILD_DUMP_CALL_STACK=1",
"-DWAMR_BUILD_LIB_PTHREAD=1",
"-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1",
"-DWAMR_BUILD_MINI_LOADER=1",
"-DWAMR_BUILD_MEMORY_PROFILING=1",
"-DWAMR_BUILD_MULTI_MODULE=1",
@ -215,23 +204,10 @@ jobs:
"-DWAMR_BUILD_TAIL_CALL=1",
"-DWAMR_DISABLE_HW_BOUND_CHECK=1",
]
os: [ubuntu-18.04, ubuntu-20.04, macos-latest]
platform: [android, linux, darwin]
os: [ubuntu-18.04, ubuntu-20.04]
platform: [android, linux]
exclude:
# uncompatiable os and platform
# ubuntu can not go with darwin
- os: ubuntu-18.04
platform: darwin
- os: ubuntu-20.04
platform: darwin
# macos can not go with android, linux
- os: macos-latest
platform: android
- os: macos-latest
platform: linux
# uncompatiable feature and platform
- os: macos-latest
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# uncompatiable mode and feature
# MULTI_MODULE only on INTERP mode
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
@ -276,20 +252,19 @@ jobs:
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_1804 }}
- os: ubuntu-20.04
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }}
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light_on_macos_latest }}
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
uses: actions/checkout@v3
# only download llvm cache when needed
- name: Get LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
if: (matrix.light == 'green') && (endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS'))
uses: actions/cache@v3
with:
path: |
./core/deps/llvm/build/bin
@ -300,7 +275,7 @@ jobs:
key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
if: (matrix.light == 'green') && (endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')) && (steps.cache_llvm.outputs.cache-hit != 'true')
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: Build iwasm
@ -324,7 +299,7 @@ jobs:
$MC_JIT_BUILD_OPTIONS,
$AOT_BUILD_OPTIONS,
]
os: [ubuntu-18.04, ubuntu-20.04, macos-latest]
os: [ubuntu-18.04, ubuntu-20.04]
include:
- os: ubuntu-18.04
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_1804 }}
@ -334,30 +309,18 @@ jobs:
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }}
wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz
wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light_on_macos_latest }}
wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz
wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz
exclude:
# TODO: a .aot compatiable problem
- os: macos-latest
make_options: $LAZY_JIT_BUILD_OPTIONS
- os: macos-latest
make_options: $AOT_BUILD_OPTIONS
- os: macos-latest
make_options: $MC_JIT_BUILD_OPTIONS
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Get LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
if: (matrix.light == 'green') && (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
uses: actions/cache@v3
with:
path: |
./core/deps/llvm/build/bin
@ -368,7 +331,7 @@ jobs:
key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
if: (matrix.light == 'green') && (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) && (steps.cache_llvm.outputs.cache-hit != 'true')
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: download and install wabt
@ -380,7 +343,7 @@ jobs:
sudo mv wabt-1.0.24 wabt
- name: Build wamrc
if: ${{ matrix.light == 'green' }}
if: (matrix.light == 'green') && (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
run: |
mkdir build && cd build
cmake ..
@ -406,7 +369,7 @@ jobs:
working-directory: samples/wasm-c-api
build_samples_others:
needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo]
needs: [build_iwasm, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
@ -419,34 +382,13 @@ jobs:
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }}
wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz
wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light_on_macos_latest }}
wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz
wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
- name: Get LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
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.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
uses: actions/checkout@v3
- name: download and install wasi-sdk
if: ${{ matrix.light == 'green' }}
@ -464,14 +406,6 @@ jobs:
sudo tar -xzf wabt-1.0.24-*.tar.gz
sudo mv wabt-1.0.24 wabt
- name: Build wamrc
if: ${{ matrix.light == 'green' }}
run: |
mkdir build && cd build
cmake ..
cmake --build . --config Release --parallel 4
working-directory: wamr-compiler
- name: Build Sample [basic]
if: ${{ matrix.light == 'green' }}
run: |
@ -514,3 +448,110 @@ jobs:
cmake ..
cmake --build . --config Release --parallel 4
./hello
spec_test_default:
needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo]
runs-on: ubuntu-20.04
strategy:
matrix:
test_option: [$DEFAULT_TEST_OPTIONS, $SIMD_TEST_OPTIONS]
steps:
- name: checkout
uses: actions/checkout@v3
- name: Get LLVM libraries
id: cache_llvm
uses: actions/cache@v3
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: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: steps.cache_llvm.outputs.cache-hit != 'true'
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: install Ninja
run: sudo apt install -y ninja-build
- name: run spec tests
run: ./test_wamr.sh ${{ matrix.test_option }}
working-directory: ./tests/wamr-test-suites
spec_test_extra:
if: ${{ endsWith(github.repository, 'wasm-micro-runtime') }}
needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo]
runs-on: ubuntu-20.04
strategy:
matrix:
test_option: [$MULTI_MODULES_TEST_OPTIONS, $THREADS_TEST_OPTIONS]
steps:
- name: checkout
uses: actions/checkout@v3
- name: Get LLVM libraries
id: cache_llvm
uses: actions/cache@v3
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: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: steps.cache_llvm.outputs.cache-hit != 'true'
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: install Ninja
run: sudo apt install -y ninja-build
- name: run spec tests
run: ./test_wamr.sh ${{ matrix.test_option }}
working-directory: ./tests/wamr-test-suites
spec_test_x86_32:
if: ${{ endsWith(github.repository, 'wasm-micro-runtime') }}
needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo]
runs-on: ubuntu-20.04
strategy:
matrix:
test_option: [$DEFAULT_TEST_OPTIONS, $THREADS_TEST_OPTIONS]
steps:
- name: checkout
uses: actions/checkout@v3
- name: Get LLVM libraries
id: cache_llvm
uses: actions/cache@v3
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: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: steps.cache_llvm.outputs.cache-hit != 'true'
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: install Ninja and x32 support libraries
run:
# Add another apt repository as some packages cannot
# be downloaded with the github default repository
sudo curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc &&
sudo apt-add-repository https://packages.microsoft.com/ubuntu/20.04/prod &&
sudo apt-get update &&
sudo apt install -y g++-multilib lib32gcc-9-dev ninja-build
- name: run spec tests
run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }}
working-directory: ./tests/wamr-test-suites

View File

@ -0,0 +1,393 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
name: compilation on macos-latest
on:
# will be triggered on PR events
pull_request:
paths-ignore:
- "assembly-script/**"
- "ci/**"
- "doc/**"
- "test-tools/**"
- ".github/workflows/compilation_on_macos.yml"
# will be triggered on push events
push:
paths-ignore:
- "assembly-script/**"
- "ci/**"
- "doc/**"
- "test-tools/**"
- ".github/workflows/compilation_on_macos.yml"
# allow to be triggered manually
workflow_dispatch:
# Cancel any in-flight jobs for the same PR/branch so there's only one active
# at a time
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
jobs:
# Cancel any in-flight jobs for the same PR/branch so there's only one active
# at a time
cancel_previous:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
steps:
- name: Cancel Workflow Action
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
# set different traffic lights based on the current repo and the running OS.
# according to light colors, the workflow will run different jobs
check_repo:
needs: cancel_previous
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
outputs:
traffic_light: ${{ steps.do_check.outputs.light }}
steps:
- name: do_check
id: do_check
if: ${{ matrix.os == 'macos-latest' }}
run: |
if [[ ${{ github.repository }} == */wasm-micro-runtime ]]; then
echo "::set-output name=light::green"
else
echo "::set-output name=light::red"
fi
build_llvm_libraries:
needs: check_repo
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
include:
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light }}
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v3
- name: Cache LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v3
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.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Build llvm and clang from source
id: build_llvm
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly
working-directory: build-scripts
build_wamrc:
needs: [build_llvm_libraries, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
include:
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light }}
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v3
- name: Get LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v3
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.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: Build wamrc
if: ${{ matrix.light == 'green' }}
run: |
mkdir build && cd build
cmake ..
cmake --build . --config Release --parallel 4
working-directory: wamr-compiler
build_iwasm:
needs: [build_llvm_libraries, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
make_options_run_mode: [
# Running mode
$AOT_BUILD_OPTIONS,
$CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS,
$LAZY_JIT_BUILD_OPTIONS,
$MC_JIT_BUILD_OPTIONS,
]
make_options_feature: [
# Features
"-DWAMR_BUILD_CUSTOM_NAME_SECTION=1",
# doesn't support
#"-DWAMR_BUILD_DEBUG_AOT=1",
"-DWAMR_BUILD_DEBUG_INTERP=1",
"-DWAMR_BUILD_DUMP_CALL_STACK=1",
"-DWAMR_BUILD_LIB_PTHREAD=1",
"-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1",
"-DWAMR_BUILD_MINI_LOADER=1",
"-DWAMR_BUILD_MEMORY_PROFILING=1",
"-DWAMR_BUILD_MULTI_MODULE=1",
"-DWAMR_BUILD_PERF_PROFILING=1",
"-DWAMR_BUILD_REF_TYPES=1",
"-DWAMR_BUILD_SIMD=1",
"-DWAMR_BUILD_TAIL_CALL=1",
"-DWAMR_DISABLE_HW_BOUND_CHECK=1",
]
os: [macos-latest]
platform: [darwin]
exclude:
# uncompatiable feature and platform
# uncompatiable mode and feature
# MULTI_MODULE only on INTERP mode
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
# SIMD only on JIT/AOT mode
- make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_SIMD=1"
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_SIMD=1"
# DEBUG_INTERP only on CLASSIC INTERP mode
- make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
# DEBUG_AOT only on JIT/AOT mode
- make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# TODO: DEBUG_AOT on JIT
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# MINI_LOADER only on INTERP mode
- make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
include:
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light }}
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v3
# only download llvm cache when needed
- name: Get LLVM libraries
id: cache_llvm
if: (matrix.light == 'green') && (endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS'))
uses: actions/cache@v3
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.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: (matrix.light == 'green') && (endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')) && (steps.cache_llvm.outputs.cache-hit != 'true')
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: Build iwasm
if: ${{ matrix.light == 'green' }}
run: |
mkdir build && cd build
cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }}
cmake --build . --config Release --parallel 4
working-directory: product-mini/platforms/${{ matrix.platform }}
build_samples_wasm_c_api:
needs: [build_iwasm, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
make_options: [
# Running mode
$CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS,
# doesn't support
#$LAZY_JIT_BUILD_OPTIONS,
#$MC_JIT_BUILD_OPTIONS,
#$AOT_BUILD_OPTIONS,
]
os: [macos-latest]
include:
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light }}
wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz
wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v3
- name: download and install wabt
if: ${{ matrix.light == 'green' }}
run: |
cd /opt
sudo wget ${{ matrix.wabt_release }}
sudo tar -xzf wabt-1.0.24-*.tar.gz
sudo mv wabt-1.0.24 wabt
- name: Build Sample [wasm-c-api]
if: ${{ matrix.light == 'green' }}
run: |
mkdir build && cd build
cmake .. ${{ matrix.make_options }}
cmake --build . --config Release --parallel 4
./callback
./callback_chain
./empty_imports
./global
./hello
./hostref
./memory
./reflect
./table
./trap
working-directory: samples/wasm-c-api
build_samples_others:
needs: [build_iwasm, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: macos-latest
light: ${{ needs.check_repo.outputs.traffic_light }}
wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz
wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v3
- name: download and install wasi-sdk
if: ${{ matrix.light == 'green' }}
run: |
cd /opt
sudo wget ${{ matrix.wasi_sdk_release }}
sudo tar -xzf wasi-sdk-12.0-*.tar.gz
sudo mv wasi-sdk-12.0 wasi-sdk
- name: download and install wabt
if: ${{ matrix.light == 'green' }}
run: |
cd /opt
sudo wget ${{ matrix.wabt_release }}
sudo tar -xzf wabt-1.0.24-*.tar.gz
sudo mv wabt-1.0.24 wabt
- name: Build Sample [basic]
if: ${{ matrix.light == 'green' }}
run: |
cd samples/basic
./build.sh
./run.sh
- name: Build Sample [multi-thread]
if: ${{ matrix.light == 'green' }}
run: |
cd samples/multi-thread
mkdir build && cd build
cmake ..
cmake --build . --config Release --parallel 4
./iwasm wasm-apps/test.wasm
- name: Build Sample [multi-module]
if: ${{ matrix.light == 'green' }}
run: |
cd samples/multi-module
mkdir build && cd build
cmake ..
cmake --build . --config Release --parallel 4
./multi_module
- name: Build Sample [spawn-thread]
if: ${{ matrix.light == 'green' }}
run: |
cd samples/spawn-thread
mkdir build && cd build
cmake ..
cmake --build . --config Release --parallel 4
./spawn_thread
- name: Build Sample [ref-types]
if: ${{ matrix.light == 'green' }}
run: |
cd samples/ref-types
mkdir build && cd build
cmake ..
cmake --build . --config Release --parallel 4
./hello

View File

@ -1,7 +1,7 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
name: CI on SGX
name: compilation on SGX
on:
# will be triggered on PR events
@ -47,7 +47,7 @@ jobs:
os: [ubuntu-20.04]
steps:
- name: Cancel Workflow Action
uses: styfle/cancel-workflow-action@0.6.0
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
@ -87,12 +87,12 @@ jobs:
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Cache LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
./core/deps/llvm/build/bin
@ -103,24 +103,24 @@ jobs:
key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Build llvm and clang from source
id: build_llvm_ubuntu
id: build_llvm
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly --project clang lldb
working-directory: build-scripts
build_iwasm:
needs: [build_llvm_libraries, check_repo]
needs: [check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
make_options_run_mode: [
# Running mode
$AOT_BUILD_OPTIONS,
$CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS,
# doesn't support
# $LAZY_JIT_BUILD_OPTIONS,
# $MC_JIT_BUILD_OPTIONS,
$AOT_BUILD_OPTIONS,
]
make_options_feature: [
# Features
@ -130,6 +130,7 @@ jobs:
# "-DWAMR_BUILD_DEBUG_INTERP=1",
"-DWAMR_BUILD_DUMP_CALL_STACK=1",
"-DWAMR_BUILD_LIB_PTHREAD=1",
"-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1",
"-DWAMR_BUILD_MINI_LOADER=1",
"-DWAMR_BUILD_MEMORY_PROFILING=1",
"-DWAMR_BUILD_MULTI_MODULE=1",
@ -160,7 +161,7 @@ jobs:
- name: install SGX SDK and necessary libraries
if: ${{ matrix.light == 'green' }}
run: |
mkdir -p /opt/intel
mkdir -p /opt/intel
cd /opt/intel
wget https://download.01.org/intel-sgx/sgx-linux/2.15/distro/ubuntu20.04-server/sgx_linux_x64_sdk_2.15.100.3.bin
chmod +x sgx_linux_x64_sdk_2.15.100.3.bin
@ -173,12 +174,51 @@ jobs:
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Build iwasm
if: ${{ matrix.light == 'green' }}
run: |
mkdir build && cd build
cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }}
cmake --build . --config Release --parallel 4
working-directory: product-mini/platforms/${{ matrix.platform }}
build_wamrc:
needs: [build_llvm_libraries, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04]
include:
- os: ubuntu-20.04
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }}
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
- name: install SGX SDK and necessary libraries
if: ${{ matrix.light == 'green' }}
run: |
mkdir -p /opt/intel
cd /opt/intel
wget https://download.01.org/intel-sgx/sgx-linux/2.15/distro/ubuntu20.04-server/sgx_linux_x64_sdk_2.15.100.3.bin
chmod +x sgx_linux_x64_sdk_2.15.100.3.bin
echo 'yes' | ./sgx_linux_x64_sdk_2.15.100.3.bin
echo 'deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main' | sudo tee /etc/apt/sources.list.d/intel-sgx.list
wget -qO - https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | sudo apt-key add -
sudo apt update
sudo apt install -y libsgx-launch libsgx-urts
source /opt/intel/sgxsdk/environment
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v3
- name: Get LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
./core/deps/llvm/build/bin
@ -192,16 +232,16 @@ jobs:
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: Build iwasm
- name: Build wamrc
if: ${{ matrix.light == 'green' }}
run: |
mkdir build && cd build
cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }}
cmake ..
cmake --build . --config Release --parallel 4
working-directory: product-mini/platforms/${{ matrix.platform }}
working-directory: wamr-compiler
build_samples_wasm_c_api:
needs: [build_iwasm, build_llvm_libraries, check_repo]
needs: [build_iwasm, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
@ -226,24 +266,7 @@ jobs:
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
- name: Get LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
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.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
uses: actions/checkout@v3
- name: download and install wabt
if: ${{ matrix.light == 'green' }}
@ -256,7 +279,7 @@ jobs:
- name: install SGX SDK and necessary libraries
if: ${{ matrix.light == 'green' }}
run: |
mkdir -p /opt/intel
mkdir -p /opt/intel
cd /opt/intel
wget https://download.01.org/intel-sgx/sgx-linux/2.15/distro/ubuntu20.04-server/sgx_linux_x64_sdk_2.15.100.3.bin
chmod +x sgx_linux_x64_sdk_2.15.100.3.bin
@ -267,14 +290,6 @@ jobs:
sudo apt install -y libsgx-launch libsgx-urts
source /opt/intel/sgxsdk/environment
- name: Build wamrc
if: ${{ matrix.light == 'green' }}
run: |
mkdir build && cd build
cmake ..
cmake --build . --config Release --parallel 4
working-directory: wamr-compiler
- name: Build Sample [wasm-c-api]
if: ${{ matrix.light == 'green' }}
run: |
@ -294,7 +309,7 @@ jobs:
working-directory: samples/wasm-c-api
build_samples_others:
needs: [build_iwasm, build_llvm_libraries, check_repo]
needs: [build_iwasm, check_repo]
runs-on: ${{ matrix.os }}
strategy:
matrix:
@ -309,24 +324,7 @@ jobs:
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
- name: Get LLVM libraries
id: cache_llvm
if: ${{ matrix.light == 'green' }}
uses: actions/cache@v2
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.os }}-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
uses: actions/checkout@v3
- name: download and install wasi-sdk
if: ${{ matrix.light == 'green' }}
@ -347,7 +345,7 @@ jobs:
- name: install SGX SDK and necessary libraries
if: ${{ matrix.light == 'green' }}
run: |
mkdir -p /opt/intel
mkdir -p /opt/intel
cd /opt/intel
wget https://download.01.org/intel-sgx/sgx-linux/2.15/distro/ubuntu20.04-server/sgx_linux_x64_sdk_2.15.100.3.bin
chmod +x sgx_linux_x64_sdk_2.15.100.3.bin
@ -358,14 +356,6 @@ jobs:
sudo apt install -y libsgx-launch libsgx-urts
source /opt/intel/sgxsdk/environment
- name: Build wamrc
if: ${{ matrix.light == 'green' }}
run: |
mkdir build && cd build
cmake ..
cmake --build . --config Release --parallel 4
working-directory: wamr-compiler
- name: Build Sample [basic]
if: ${{ matrix.light == 'green' }}
run: |
@ -410,7 +400,7 @@ jobs:
./hello
spec_test_default:
needs: [build_iwasm, build_llvm_libraries, check_repo]
needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo]
runs-on: ubuntu-20.04
strategy:
matrix:
@ -422,12 +412,12 @@ jobs:
steps:
- name: checkout
if: ${{ matrix.light == 'green' }}
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Get LLVM libraries
if: ${{ matrix.light == 'green' }}
id: cache_llvm
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
./core/deps/llvm/build/bin
@ -437,6 +427,10 @@ jobs:
./core/deps/llvm/build/share
key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }}
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: install Ninja
if: ${{ matrix.light == 'green' }}
run: sudo apt install -y ninja-build
@ -444,7 +438,7 @@ jobs:
- name: install SGX SDK and necessary libraries
if: ${{ matrix.light == 'green' }}
run: |
mkdir -p /opt/intel
mkdir -p /opt/intel
cd /opt/intel
wget https://download.01.org/intel-sgx/sgx-linux/2.15/distro/ubuntu20.04-server/sgx_linux_x64_sdk_2.15.100.3.bin
chmod +x sgx_linux_x64_sdk_2.15.100.3.bin

View File

@ -36,7 +36,7 @@ jobs:
runs-on: windows-latest
steps:
- name: Cancel Workflow Action
uses: styfle/cancel-workflow-action@0.6.0
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
@ -44,7 +44,7 @@ jobs:
needs: cancel_previous
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: clone uvwasi library
run: |

View File

@ -1,155 +0,0 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
name: Spec tests on non-windows
on:
# will be triggered on PR events
pull_request:
paths:
- "core/config.h"
- "core/iwasm/**"
- "core/shared/**"
- "wamr-compiler/**"
- "product-mini/**"
- "tests/wamr-test-suites/spec-test-script/**"
- "tests/wamr-test-suites/test_wamr.sh"
- ".github/workflows/spec_test.yml"
# will be triggered on push events
push:
paths:
- "core/config.h"
- "core/iwasm/**"
- "core/shared/**"
- "wamr-compiler/**"
- "product-mini/**"
- "tests/wamr-test-suites/spec-test-script/**"
- "tests/wamr-test-suites/test_wamr.sh"
- ".github/workflows/spec_test.yml"
# allow to be triggered manually
workflow_dispatch:
# Cancel any in-flight jobs for the same PR/branch so there's only one active
# at a time
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
DEFAULT_TEST_OPTIONS: "-s spec -P"
LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"
MULTI_MODULES_TEST_OPTIONS: "-s spec -M -P"
SIMD_TEST_OPTIONS: "-s spec -S -P"
THREADS_TEST_OPTIONS: "-s spec -p -P"
X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
jobs:
cancel_previous:
runs-on: ubuntu-20.04
steps:
- name: Cancel Workflow Action
uses: styfle/cancel-workflow-action@0.6.0
with:
access_token: ${{ github.token }}
spec_test_default:
needs: cancel_previous
runs-on: ubuntu-20.04
strategy:
matrix:
test_option: [$DEFAULT_TEST_OPTIONS, $SIMD_TEST_OPTIONS]
steps:
- name: checkout
uses: actions/checkout@v2
- name: Get LLVM libraries
id: cache_llvm
uses: actions/cache@v2
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: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
- name: install Ninja
run: sudo apt install -y ninja-build
- name: run spec tests
run: ./test_wamr.sh ${{ matrix.test_option }}
working-directory: ./tests/wamr-test-suites
spec_test_extra:
needs: cancel_previous
if: ${{ endsWith(github.repository, 'wasm-micro-runtime') }}
runs-on: ubuntu-20.04
strategy:
matrix:
test_option: [$MULTI_MODULES_TEST_OPTIONS, $THREADS_TEST_OPTIONS]
steps:
- name: checkout
uses: actions/checkout@v2
- name: Get LLVM libraries
id: cache_llvm
uses: actions/cache@v2
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: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: steps.cache_llvm.outputs.cache-hit != 'true'
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: install Ninja
run: sudo apt install -y ninja-build
- name: run spec tests
run: ./test_wamr.sh ${{ matrix.test_option }}
working-directory: ./tests/wamr-test-suites
spec_test_x86_32:
if: ${{ endsWith(github.repository, 'wasm-micro-runtime') }}
needs: cancel_previous
runs-on: ubuntu-20.04
strategy:
matrix:
test_option: [$DEFAULT_TEST_OPTIONS, $THREADS_TEST_OPTIONS]
steps:
- name: checkout
uses: actions/checkout@v2
- name: Get LLVM libraries
id: cache_llvm
uses: actions/cache@v2
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: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }}
- name: Quit if cache miss
if: steps.cache_llvm.outputs.cache-hit != 'true'
run: echo "::error::can not get prebuilt llvm libraries" && exit 1
- name: install Ninja and x32 support libraries
run:
# Add another apt repository as some packages cannot
# be downloaded with the github default repository
sudo curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc &&
sudo apt-add-repository https://packages.microsoft.com/ubuntu/20.04/prod &&
sudo apt-get update &&
sudo apt install -y g++-multilib lib32gcc-9-dev ninja-build
- name: run spec tests
run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }}
working-directory: ./tests/wamr-test-suites

View File

@ -19,6 +19,8 @@ Getting started
==================
- [Build iwasm VM core](./doc/build_wamr.md) on [Linux](./doc/build_wamr.md#linux), [SGX](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos) and [Windows](./doc/build_wamr.md#windows), and [Build wamrc AOT compiler](./README.md#build-wamrc-aot-compiler)
- [Embed WAMR into host applications](./doc/embed_wamr.md)
- [Embed into C/C++](./doc/embed_wamr.md), [Embed into Python](./language-bindings/python), [Embed into Go](./language-bindings/go)
- [Register native APIs for WASM applications](./doc/export_native_api.md)
- [Build WASM applications](./doc/build_wasm_app.md)
- [Port WAMR to a new platform](./doc/port_wamr.md)

View File

@ -259,3 +259,7 @@ endif ()
if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
message (" Debug AOT enabled")
endif ()
if (WAMR_BUILD_LOAD_CUSTOM_SECTION EQUAL 1)
add_definitions (-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)
message (" Load custom section enabled")
endif ()

View File

@ -176,6 +176,11 @@
#define WASM_ENABLE_DEBUG_AOT 0
#endif
/* Custom sections */
#ifndef WASM_ENABLE_LOAD_CUSTOM_SECTION
#define WASM_ENABLE_LOAD_CUSTOM_SECTION 0
#endif
/* WASM log system */
#ifndef WASM_ENABLE_LOG
#define WASM_ENABLE_LOG 1

View File

@ -14,6 +14,7 @@
#include "../compilation/aot_llvm.h"
#include "../interpreter/wasm_loader.h"
#endif
#if WASM_ENABLE_DEBUG_AOT != 0
#include "debug/elf_parser.h"
#include "debug/jit_debug.h"
@ -151,7 +152,7 @@ GET_U64_FROM_ADDR(uint32 *addr)
#define read_byte_array(p, p_end, addr, len) \
do { \
CHECK_BUF(p, p_end, len); \
memcpy(addr, p, len); \
bh_memcpy_s(addr, len, p, len); \
p += len; \
} while (0)
@ -674,6 +675,36 @@ load_custom_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
error_buf, error_buf_size))
goto fail;
break;
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
case AOT_CUSTOM_SECTION_RAW:
{
const char *section_name;
WASMCustomSection *section;
if (p >= p_end) {
set_error_buf(error_buf, error_buf_size, "unexpected end");
goto fail;
}
read_string(p, p_end, section_name);
section = loader_malloc(sizeof(WASMCustomSection), error_buf,
error_buf_size);
if (!section) {
goto fail;
}
section->name_addr = (char *)section_name;
section->name_len = strlen(section_name);
section->content_addr = (uint8 *)p;
section->content_len = p_end - p;
section->next = module->custom_section_list;
module->custom_section_list = section;
LOG_VERBOSE("Load custom section [%s] success.", section_name);
break;
}
#endif /* end of WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 */
default:
break;
}
@ -1816,7 +1847,7 @@ do_text_relocation(AOTModule *module, AOTRelocationGroup *group,
return false;
}
}
memcpy(symbol, relocation->symbol_name, symbol_len);
bh_memcpy_s(symbol, symbol_len, relocation->symbol_name, symbol_len);
symbol[symbol_len] = '\0';
if (!strncmp(symbol, AOT_FUNC_PREFIX, strlen(AOT_FUNC_PREFIX))) {
@ -3261,6 +3292,10 @@ aot_unload(AOTModule *module)
}
#endif
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
wasm_runtime_destroy_custom_sections(module->custom_section_list);
#endif
wasm_runtime_free(module);
}
@ -3269,3 +3304,24 @@ aot_get_plt_table_size()
{
return get_plt_table_size();
}
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
const uint8 *
aot_get_custom_section(const AOTModule *module, const char *name, uint32 *len)
{
WASMCustomSection *section = module->custom_section_list;
while (section) {
if (strcmp(section->name_addr, name) == 0) {
if (len) {
*len = section->content_len;
}
return section->content_addr;
}
section = section->next;
}
return NULL;
}
#endif /* end of WASM_ENABLE_LOAD_CUSTOM_SECTION */

View File

@ -1837,7 +1837,7 @@ aot_module_realloc(AOTModuleInstance *module_inst, uint32 ptr, uint32 size,
if (memory_inst->heap_handle.ptr) {
addr = mem_allocator_realloc(
memory_inst->heap_handle.ptr,
(uint8 *)memory_inst->memory_data.ptr + ptr, size);
ptr ? (uint8 *)memory_inst->memory_data.ptr + ptr : NULL, size);
}
/* Only support realloc in WAMR's app heap */

View File

@ -50,6 +50,7 @@ typedef enum AOTSectionType {
} AOTSectionType;
typedef enum AOTCustomSectionType {
AOT_CUSTOM_SECTION_RAW = 0,
AOT_CUSTOM_SECTION_NATIVE_SYMBOL = 1,
AOT_CUSTOM_SECTION_ACCESS_CONTROL = 2,
AOT_CUSTOM_SECTION_NAME = 3,
@ -268,6 +269,9 @@ typedef struct AOTModule {
uint32 *aux_func_indexes;
uint32 aux_func_name_count;
#endif
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
WASMCustomSection *custom_section_list;
#endif
} AOTModule;
typedef union {
@ -733,6 +737,9 @@ aot_dump_call_stack(WASMExecEnv *exec_env);
void
aot_dump_perf_profiling(const AOTModuleInstance *module_inst);
const uint8 *
aot_get_custom_section(const AOTModule *module, const char *name, uint32 *len);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -13,6 +13,7 @@
#define R_ARC_32_ME 27
/* clang-format off */
#ifndef __CCAC__
void __st_r13_to_r15();
void __st_r13_to_r16();
void __st_r13_to_r17();
@ -41,29 +42,86 @@ void __divdf3();
void __divdi3();
void __divsf3();
void __divsi3();
void __eqsf2();
void __extendsfdf2();
void __fixdfsi();
void __floatsidf();
void __floatsisf();
void __gedf2();
void __gtdf2();
void __ledf2();
void __lesf2();
void __ltdf2();
void __muldf3();
void __mulsf3();
void __subdf3();
void __subsf3();
void __truncdfsf2();
#else
void __ac_push_13_to_13();
void __ac_push_13_to_14();
void __ac_push_13_to_15();
void __ac_push_13_to_16();
void __ac_push_13_to_17();
void __ac_push_13_to_18();
void __ac_push_13_to_19();
void __ac_push_13_to_20();
void __ac_push_13_to_21();
void __ac_push_13_to_22();
void __ac_push_13_to_23();
void __ac_push_13_to_24();
void __ac_push_13_to_25();
void __ac_push_13_to_26();
void __ac_push_none();
void __ac_pop_13_to_26();
void __ac_pop_13_to_26v();
void __ac_pop_13_to_25();
void __ac_pop_13_to_25v();
void __ac_pop_13_to_24();
void __ac_pop_13_to_24v();
void __ac_pop_13_to_23();
void __ac_pop_13_to_23v();
void __ac_pop_13_to_22();
void __ac_pop_13_to_22v();
void __ac_pop_13_to_21();
void __ac_pop_13_to_21v();
void __ac_pop_13_to_20();
void __ac_pop_13_to_20v();
void __ac_pop_13_to_19();
void __ac_pop_13_to_19v();
void __ac_pop_13_to_18();
void __ac_pop_13_to_18v();
void __ac_pop_13_to_17();
void __ac_pop_13_to_17v();
void __ac_pop_13_to_16();
void __ac_pop_13_to_16v();
void __ac_pop_13_to_15();
void __ac_pop_13_to_15v();
void __ac_pop_13_to_14();
void __ac_pop_13_to_14v();
void __ac_pop_13_to_13();
void __ac_pop_13_to_13v();
void __ac_pop_none();
void __ac_pop_nonev();
void __eqdf2();
void __nedf2();
void __ltsf2();
void __nesf2();
void __gesf2();
void __gtsf2();
void __unordsf2();
void __truncdfhf2();
void __truncsfhf2();
#endif /* end of __CCAC__ */
void __ledf2();
void __ltdf2();
void __gedf2();
void __gtdf2();
void __eqsf2();
void __lesf2();
void __unorddf2();
/* clang-format on */
static SymbolMap target_sym_map[] = {
/* clang-format off */
REG_COMMON_SYMBOLS
#ifndef __CCAC__
REG_SYM(__st_r13_to_r15),
/* clang-format on */
REG_SYM(__st_r13_to_r16),
REG_SYM(__st_r13_to_r17),
REG_SYM(__st_r13_to_r18),
@ -91,22 +149,80 @@ static SymbolMap target_sym_map[] = {
REG_SYM(__divdi3),
REG_SYM(__divsf3),
REG_SYM(__divsi3),
REG_SYM(__eqsf2),
REG_SYM(__extendsfdf2),
REG_SYM(__fixdfsi),
REG_SYM(__floatsidf),
REG_SYM(__floatsisf),
REG_SYM(__gedf2),
REG_SYM(__gtdf2),
REG_SYM(__ledf2),
REG_SYM(__lesf2),
REG_SYM(__ltdf2),
REG_SYM(__muldf3),
REG_SYM(__mulsf3),
REG_SYM(__subdf3),
REG_SYM(__subsf3),
REG_SYM(__truncdfsf2),
#else
REG_SYM(__ac_push_13_to_13),
REG_SYM(__ac_push_13_to_14),
REG_SYM(__ac_push_13_to_15),
REG_SYM(__ac_push_13_to_16),
REG_SYM(__ac_push_13_to_17),
REG_SYM(__ac_push_13_to_18),
REG_SYM(__ac_push_13_to_19),
REG_SYM(__ac_push_13_to_20),
REG_SYM(__ac_push_13_to_21),
REG_SYM(__ac_push_13_to_22),
REG_SYM(__ac_push_13_to_23),
REG_SYM(__ac_push_13_to_24),
REG_SYM(__ac_push_13_to_25),
REG_SYM(__ac_push_13_to_26),
REG_SYM(__ac_push_none),
REG_SYM(__ac_pop_13_to_26),
REG_SYM(__ac_pop_13_to_26v),
REG_SYM(__ac_pop_13_to_25),
REG_SYM(__ac_pop_13_to_25v),
REG_SYM(__ac_pop_13_to_24),
REG_SYM(__ac_pop_13_to_24v),
REG_SYM(__ac_pop_13_to_23),
REG_SYM(__ac_pop_13_to_23v),
REG_SYM(__ac_pop_13_to_22),
REG_SYM(__ac_pop_13_to_22v),
REG_SYM(__ac_pop_13_to_21),
REG_SYM(__ac_pop_13_to_21v),
REG_SYM(__ac_pop_13_to_20),
REG_SYM(__ac_pop_13_to_20v),
REG_SYM(__ac_pop_13_to_19),
REG_SYM(__ac_pop_13_to_19v),
REG_SYM(__ac_pop_13_to_18),
REG_SYM(__ac_pop_13_to_18v),
REG_SYM(__ac_pop_13_to_17),
REG_SYM(__ac_pop_13_to_17v),
REG_SYM(__ac_pop_13_to_16),
REG_SYM(__ac_pop_13_to_16v),
REG_SYM(__ac_pop_13_to_15),
REG_SYM(__ac_pop_13_to_15v),
REG_SYM(__ac_pop_13_to_14),
REG_SYM(__ac_pop_13_to_14v),
REG_SYM(__ac_pop_13_to_13),
REG_SYM(__ac_pop_13_to_13v),
REG_SYM(__ac_pop_none),
REG_SYM(__ac_pop_nonev),
REG_SYM(__eqdf2),
REG_SYM(__nedf2),
REG_SYM(__ltsf2),
REG_SYM(__nesf2),
REG_SYM(__gesf2),
REG_SYM(__gtsf2),
REG_SYM(__unordsf2),
REG_SYM(__truncdfhf2),
REG_SYM(__truncsfhf2),
#endif /* end of __CCAC__ */
REG_SYM(__ledf2),
REG_SYM(__ltdf2),
REG_SYM(__gedf2),
REG_SYM(__gtdf2),
REG_SYM(__eqsf2),
REG_SYM(__lesf2),
REG_SYM(__unorddf2),
/* clang-format on */
};
static void
@ -168,6 +284,45 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
int32 symbol_index, char *error_buf, uint32 error_buf_size)
{
switch (reloc_type) {
case R_ARC_S25H_PCREL:
{
uint32 insn = LOAD_I32(target_section_addr + reloc_offset);
int32 addend, value;
uintptr_t S, P;
intptr_t A;
CHECK_RELOC_OFFSET(sizeof(void *));
/* Convert from middle endian */
insn = middle_endian_convert(insn);
addend = ((insn << 28) >> 28) << 10;
/* Extract the next 10 bits from Position 6 to 15 in insn */
addend |= ((insn << 16) >> 22);
addend = addend << 10;
/* Extract the remaining 10 bits from Position 17 to 26 in insn */
addend |= ((insn << 5) >> 22);
/* Fill in 1 bits to get the 25 bit Offset Value */
addend = addend << 1;
/* (S + A) - P */
S = (uintptr_t)(uint8 *)symbol_addr;
A = (intptr_t)reloc_addend;
P = (uintptr_t)(target_section_addr + reloc_offset);
P &= (uintptr_t)~1;
value = (int32)(S + A + addend - P);
insn = insn & 0xf8010030;
insn |= ((((value >> 1) & 0x3ff) << 17)
| (((value >> 1) & 0xffc00) >> 3)
| (((value >> 1) & 0xf00000) >> 19));
/* Convert to middle endian */
insn = middle_endian_convert(insn);
STORE_U32(target_section_addr + reloc_offset, insn);
break;
}
case R_ARC_S25W_PCREL:
{
uint32 insn = LOAD_I32(target_section_addr + reloc_offset);

View File

@ -22,6 +22,26 @@ void __modsi3();
void __divdi3();
void __udivdi3();
void __unorddf2();
void __adddf3();
void __eqdf2();
void __muldf3();
void __gedf2();
void __ledf2();
void __fixunsdfsi();
void __floatunsidf();
void __subdf3();
void __nedf2();
void __fixdfsi();
void __moddi3();
void __extendsfdf2();
void __truncdfsf2();
void __gtdf2();
void __umoddi3();
void __floatdidf();
void __divsf3();
static SymbolMap target_sym_map[] = {
REG_COMMON_SYMBOLS
@ -40,6 +60,28 @@ static SymbolMap target_sym_map[] = {
REG_SYM(__modsi3),
REG_SYM(__divdi3),
REG_SYM(__udivdi3),
REG_SYM(__unorddf2),
REG_SYM(__adddf3),
REG_SYM(__eqdf2),
REG_SYM(__muldf3),
REG_SYM(__gedf2),
REG_SYM(__ledf2),
REG_SYM(__fixunsdfsi),
REG_SYM(__floatunsidf),
REG_SYM(__subdf3),
REG_SYM(__nedf2),
REG_SYM(__fixdfsi),
REG_SYM(__moddi3),
REG_SYM(__extendsfdf2),
REG_SYM(__truncdfsf2),
REG_SYM(__gtdf2),
REG_SYM(__umoddi3),
REG_SYM(__floatdidf),
REG_SYM(__divsf3),
REG_SYM(sqrt),
REG_SYM(sqrtf),
};
/* clang-format on */
@ -130,6 +172,16 @@ static union {
#define is_little_endian() (__ue.b == 1)
#if !defined(__packed)
/*
* Note: This version check is a bit relaxed.
* The __packed__ attribute has been there since gcc 2 era.
*/
#if __GNUC__ >= 3
#define __packed __attribute__((__packed__))
#endif
#endif
typedef union {
struct l32r_le {
int8 other;

View File

@ -485,7 +485,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
u.ieee.ieee_little_endian.negative = 1;
else
u.ieee.ieee_big_endian.negative = 1;
memcpy(&f32, &u.f, sizeof(float));
bh_memcpy_s(&f32, sizeof(float), &u.f, sizeof(float));
}
if (endptr[0] == ':') {
uint32 sig;
@ -496,10 +496,11 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
u.ieee.ieee_little_endian.mantissa = sig;
else
u.ieee.ieee_big_endian.mantissa = sig;
memcpy(&f32, &u.f, sizeof(float));
bh_memcpy_s(&f32, sizeof(float), &u.f, sizeof(float));
}
}
memcpy(&argv1[p++], &f32, sizeof(float));
bh_memcpy_s(&argv1[p], total_size - p, &f32, sizeof(float));
p++;
break;
}
case VALUE_TYPE_F64:
@ -517,7 +518,8 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
ud.ieee.ieee_little_endian.negative = 1;
else
ud.ieee.ieee_big_endian.negative = 1;
memcpy(&u.val, &ud.d, sizeof(double));
bh_memcpy_s(&u.val, sizeof(double), &ud.d,
sizeof(double));
}
if (endptr[0] == ':') {
uint64 sig;
@ -532,7 +534,8 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
ud.ieee.ieee_big_endian.mantissa0 = sig >> 32;
ud.ieee.ieee_big_endian.mantissa1 = (uint32)sig;
}
memcpy(&u.val, &ud.d, sizeof(double));
bh_memcpy_s(&u.val, sizeof(double), &ud.d,
sizeof(double));
}
}
argv1[p++] = u.parts[0];
@ -755,7 +758,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
}
#endif
#if WAMR_ENABLE_PERF_PROFILING != 0
#if WASM_ENABLE_PERF_PROFILING != 0
wasm_runtime_dump_perf_profiling(module_inst);
#endif

View File

@ -464,7 +464,7 @@ wasm_runtime_register_module_internal(const char *module_name,
WASMModuleCommon *module,
uint8 *orig_file_buf,
uint32 orig_file_buf_size,
char *error_buf, uint32_t error_buf_size)
char *error_buf, uint32 error_buf_size)
{
WASMRegisteredModule *node = NULL;
@ -519,7 +519,7 @@ wasm_runtime_register_module_internal(const char *module_name,
bool
wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module,
char *error_buf, uint32_t error_buf_size)
char *error_buf, uint32 error_buf_size)
{
if (!error_buf || !error_buf_size) {
LOG_ERROR("error buffer is required");
@ -842,7 +842,7 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
WASMModuleCommon *
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
char *error_buf, uint32_t error_buf_size)
char *error_buf, uint32 error_buf_size)
{
WASMModuleCommon *module_common;
@ -999,6 +999,23 @@ wasm_runtime_destroy_thread_env(void)
#endif
}
bool
wasm_runtime_thread_env_inited(void)
{
#ifdef BH_PLATFORM_WINDOWS
if (!os_thread_env_inited())
return false;
#endif
#if WASM_ENABLE_AOT != 0
#ifdef OS_ENABLE_HW_BOUND_CHECK
if (!os_thread_signal_inited())
return false;
#endif
#endif
return true;
}
#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0)
void
wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module)
@ -1241,8 +1258,85 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst,
return NULL;
}
uint32
wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst)
{
WASMType *type =
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
bh_assert(type);
return type->param_count;
}
uint32
wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst)
{
WASMType *type =
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
bh_assert(type);
return type->result_count;
}
static uint8
val_type_to_val_kind(uint8 value_type)
{
switch (value_type) {
case VALUE_TYPE_I32:
return WASM_I32;
case VALUE_TYPE_I64:
return WASM_I64;
case VALUE_TYPE_F32:
return WASM_F32;
case VALUE_TYPE_F64:
return WASM_F64;
case VALUE_TYPE_FUNCREF:
return WASM_FUNCREF;
case VALUE_TYPE_EXTERNREF:
return WASM_ANYREF;
default:
bh_assert(0);
return 0;
}
}
void
wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst,
wasm_valkind_t *param_types)
{
WASMType *type =
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
uint32 i;
bh_assert(type);
for (i = 0; i < type->param_count; i++) {
param_types[i] = val_type_to_val_kind(type->types[i]);
}
}
void
wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst,
wasm_valkind_t *result_types)
{
WASMType *type =
wasm_runtime_get_function_type(func_inst, module_inst->module_type);
uint32 i;
bh_assert(type);
for (i = 0; i < type->result_count; i++) {
result_types[i] =
val_type_to_val_kind(type->types[type->param_count + i]);
}
}
#if WASM_ENABLE_REF_TYPES != 0
/* (uintptr_t)externref -> (uint32_t)index */
/* (uintptr_t)externref -> (uint32)index */
/* argv -> *ret_argv */
static bool
wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
@ -1340,7 +1434,7 @@ wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
return true;
}
/* (uintptr_t)externref <- (uint32_t)index */
/* (uintptr_t)externref <- (uint32)index */
/* argv <- new_argv */
static bool
wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
@ -2776,6 +2870,24 @@ wasm_exec_env_get_module(WASMExecEnv *exec_env)
return NULL;
}
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
const uint8 *
wasm_runtime_get_custom_section(WASMModuleCommon *const module_comm,
const char *name, uint32 *len)
{
#if WASM_ENABLE_INTERP != 0
if (module_comm->module_type == Wasm_Module_Bytecode)
return wasm_loader_get_custom_section((WASMModule *)module_comm, name,
len);
#endif
#if WASM_ENABLE_AOT != 0
if (module_comm->module_type == Wasm_Module_AoT)
return aot_get_custom_section((AOTModule *)module_comm, name, len);
#endif
return NULL;
}
#endif /* end of WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 */
static union {
int a;
char b;
@ -3971,8 +4083,8 @@ fail:
|| defined(BUILD_TARGET_RISCV64_LP64) */
bool
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices,
uint32_t argc, uint32_t argv[])
wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
uint32 argc, uint32 argv[])
{
if (!wasm_runtime_exec_env_check(exec_env)) {
LOG_ERROR("Invalid exec env stack info.");
@ -4820,3 +4932,16 @@ wasm_runtime_show_app_heap_corrupted_prompt()
"compiled by asc, please add --exportRuntime to "
"export the runtime helpers.");
}
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
void
wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list)
{
WASMCustomSection *section = section_list, *next;
while (section) {
next = section->next;
wasm_runtime_free(section);
section = next;
}
}
#endif /* end of WASM_ENABLE_LOAD_CUSTOM_SECTION */

View File

@ -303,6 +303,11 @@ typedef struct WASMModuleCommon {
Wasm_Module_AoT, and this structure should be treated as
AOTModule structure. */
uint32 module_type;
/* The following uint8[1] member is a dummy just to indicate
some module_type dependent members follow.
Typically it should be accessed by casting to the corresponding
actual module_type dependent structure, not via this member. */
uint8 module_data[1];
} WASMModuleCommon;
@ -314,6 +319,11 @@ typedef struct WASMModuleInstanceCommon {
Wasm_Module_AoT, and this structure should be treated as
AOTModuleInstance structure. */
uint32 module_type;
/* The following uint8[1] member is a dummy just to indicate
some module_type dependent members follow.
Typically it should be accessed by casting to the corresponding
actual module_type dependent structure, not via this member. */
uint8 module_inst_data[1];
} WASMModuleInstanceCommon;
@ -377,6 +387,11 @@ typedef struct WASMRegisteredModule {
typedef struct WASMMemoryInstanceCommon {
uint32 module_type;
/* The following uint8[1] member is a dummy just to indicate
some module_type dependent members follow.
Typically it should be accessed by casting to the corresponding
actual module_type dependent structure, not via this member. */
uint8 memory_inst_data[1];
} WASMMemoryInstanceCommon;
@ -456,6 +471,28 @@ WASMType *
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
uint32 module_type);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN uint32
wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN uint32
wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN void
wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst,
wasm_valkind_t *param_types);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN void
wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst,
WASMModuleInstanceCommon *const module_inst,
wasm_valkind_t *result_types);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN WASMExecEnv *
wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
@ -621,6 +658,11 @@ wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst,
uint8 **p_native_start_addr,
uint8 **p_native_end_addr);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN const uint8 *
wasm_runtime_get_custom_section(WASMModuleCommon *const module_comm,
const char *name, uint32 *len);
uint32
wasm_runtime_get_temp_ret(WASMModuleInstanceCommon *module_inst);
@ -842,6 +884,11 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
void
wasm_runtime_show_app_heap_corrupted_prompt();
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
void
wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -15,7 +15,9 @@
extern "C" {
#endif
#ifndef AOT_FUNC_PREFIX
#define AOT_FUNC_PREFIX "aot_func#"
#endif
typedef InitializerExpression AOTInitExpr;
typedef WASMType AOTFuncType;

View File

@ -2886,6 +2886,36 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
return true;
}
#if !(defined(_WIN32) || defined(_WIN32_))
char *
aot_generate_tempfile_name(const char *prefix, const char *extension,
char *buffer, uint32 len)
{
int fd, name_len;
name_len = snprintf(buffer, len, "%s-XXXXXX", prefix);
if ((fd = mkstemp(buffer)) <= 0) {
aot_set_last_error("make temp file failed.");
return NULL;
}
/* close and remove temp file */
close(fd);
unlink(buffer);
/* Check if buffer length is enough */
/* name_len + '.' + extension + '\0' */
if (name_len + 1 + strlen(extension) + 1 > len) {
aot_set_last_error("temp file name too long.");
return NULL;
}
snprintf(buffer + name_len, len - name_len, ".%s", extension);
return buffer;
}
#endif /* end of !(defined(_WIN32) || defined(_WIN32_)) */
#if WASM_ENABLE_LAZY_JIT == 0
bool
aot_emit_llvm_file(AOTCompContext *comp_ctx, const char *file_name)
@ -2915,6 +2945,83 @@ aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name)
bh_print_time("Begin to emit object file");
#if !(defined(_WIN32) || defined(_WIN32_))
if (comp_ctx->external_llc_compiler || comp_ctx->external_asm_compiler) {
char cmd[1024];
int ret;
if (comp_ctx->external_llc_compiler) {
char bc_file_name[64];
if (!aot_generate_tempfile_name("wamrc-bc", "bc", bc_file_name,
sizeof(bc_file_name))) {
return false;
}
if (LLVMWriteBitcodeToFile(comp_ctx->module, bc_file_name) != 0) {
aot_set_last_error("emit llvm bitcode file failed.");
return false;
}
snprintf(cmd, sizeof(cmd), "%s %s -o %s %s",
comp_ctx->external_llc_compiler,
comp_ctx->llc_compiler_flags ? comp_ctx->llc_compiler_flags
: "-O3 -c",
file_name, bc_file_name);
LOG_VERBOSE("invoking external LLC compiler:\n\t%s", cmd);
ret = system(cmd);
/* remove temp bitcode file */
unlink(bc_file_name);
if (ret != 0) {
aot_set_last_error("failed to compile LLVM bitcode to obj file "
"with external LLC compiler.");
return false;
}
}
else if (comp_ctx->external_asm_compiler) {
char asm_file_name[64];
if (!aot_generate_tempfile_name("wamrc-asm", "s", asm_file_name,
sizeof(asm_file_name))) {
return false;
}
if (LLVMTargetMachineEmitToFile(comp_ctx->target_machine,
comp_ctx->module, asm_file_name,
LLVMAssemblyFile, &err)
!= 0) {
if (err) {
LLVMDisposeMessage(err);
err = NULL;
}
aot_set_last_error("emit elf to assembly file failed.");
return false;
}
snprintf(cmd, sizeof(cmd), "%s %s -o %s %s",
comp_ctx->external_asm_compiler,
comp_ctx->asm_compiler_flags ? comp_ctx->asm_compiler_flags
: "-O3 -c",
file_name, asm_file_name);
LOG_VERBOSE("invoking external ASM compiler:\n\t%s", cmd);
ret = system(cmd);
/* remove temp assembly file */
unlink(asm_file_name);
if (ret != 0) {
aot_set_last_error("failed to compile Assembly file to obj "
"file with external ASM compiler.");
return false;
}
}
return true;
}
#endif /* end of !(defined(_WIN32) || defined(_WIN32_)) */
if (!strncmp(LLVMGetTargetName(target), "arc", 3))
/* Emit to assmelby file instead for arc target
as it cannot emit to object file */

View File

@ -371,6 +371,10 @@ aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data,
bool
aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name);
char *
aot_generate_tempfile_name(const char *prefix, const char *extension,
char *buffer, uint32 len);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -877,11 +877,15 @@ get_native_symbol_list_size(AOTCompContext *comp_ctx)
static uint32
get_name_section_size(AOTCompData *comp_data);
static uint32
get_custom_sections_size(AOTCompContext *comp_ctx, AOTCompData *comp_data);
static uint32
get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data,
AOTObjectData *obj_data)
{
uint32 size = 0;
uint32 size_custom_section = 0;
/* aot file header */
size += get_file_header_size();
@ -939,6 +943,12 @@ get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data,
get_name_section_size(comp_data));
}
size_custom_section = get_custom_sections_size(comp_ctx, comp_data);
if (size_custom_section > 0) {
size = align_uint(size, 4);
size += size_custom_section;
}
return size;
}
@ -1274,6 +1284,40 @@ fail:
return 0;
}
static uint32
get_custom_sections_size(AOTCompContext *comp_ctx, AOTCompData *comp_data)
{
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
uint32 size = 0, i;
for (i = 0; i < comp_ctx->custom_sections_count; i++) {
const char *section_name = comp_ctx->custom_sections_wp[i];
const uint8 *content = NULL;
uint32 length = 0;
content = wasm_loader_get_custom_section(comp_data->wasm_module,
section_name, &length);
if (!content) {
LOG_WARNING("Can't find custom section [%s], ignore it",
section_name);
continue;
}
size = align_uint(size, 4);
/* section id + section size + sub section id */
size += (uint32)sizeof(uint32) * 3;
/* section name and len */
size += get_string_size(comp_ctx, section_name);
/* section content */
size += length;
}
return size;
#else
return 0;
#endif
}
static bool
aot_emit_file_header(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
AOTCompData *comp_data, AOTObjectData *obj_data)
@ -1897,6 +1941,43 @@ aot_emit_name_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
return true;
}
static bool
aot_emit_custom_sections(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
AOTCompData *comp_data, AOTCompContext *comp_ctx)
{
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
uint32 offset = *p_offset, i;
for (i = 0; i < comp_ctx->custom_sections_count; i++) {
const char *section_name = comp_ctx->custom_sections_wp[i];
const uint8 *content = NULL;
uint32 length = 0;
content = wasm_loader_get_custom_section(comp_data->wasm_module,
section_name, &length);
if (!content) {
/* Warning has been reported during calculating size */
continue;
}
offset = align_uint(offset, 4);
EMIT_U32(AOT_SECTION_TYPE_CUSTOM);
/* sub section id + content */
EMIT_U32(sizeof(uint32) * 1 + get_string_size(comp_ctx, section_name)
+ length);
EMIT_U32(AOT_CUSTOM_SECTION_RAW);
EMIT_STR(section_name);
bh_memcpy_s((uint8 *)(buf + offset), (uint32)(buf_end - buf), content,
length);
offset += length;
}
*p_offset = offset;
#endif
return true;
}
typedef uint32 U32;
typedef int32 I32;
typedef uint16 U16;
@ -2611,8 +2692,41 @@ aot_obj_data_create(AOTCompContext *comp_ctx)
memset(obj_data, 0, sizeof(AOTObjectData));
bh_print_time("Begin to emit object file");
if (comp_ctx->external_llc_compiler || comp_ctx->external_asm_compiler) {
#if defined(_WIN32) || defined(_WIN32_)
aot_set_last_error("external toolchain not supported on Windows");
goto fail;
#else
/* Generate a temp file name */
int ret;
char obj_file_name[64];
if (!strncmp(LLVMGetTargetName(target), "arc", 3)) {
if (!aot_generate_tempfile_name("wamrc-obj", "o", obj_file_name,
sizeof(obj_file_name))) {
goto fail;
}
if (!aot_emit_object_file(comp_ctx, obj_file_name)) {
goto fail;
}
/* create memory buffer from object file */
ret = LLVMCreateMemoryBufferWithContentsOfFile(
obj_file_name, &obj_data->mem_buf, &err);
/* remove temp object file */
unlink(obj_file_name);
if (ret != 0) {
if (err) {
LLVMDisposeMessage(err);
err = NULL;
}
aot_set_last_error("create mem buffer with file failed.");
goto fail;
}
#endif /* end of defined(_WIN32) || defined(_WIN32_) */
}
else if (!strncmp(LLVMGetTargetName(target), "arc", 3)) {
#if defined(_WIN32) || defined(_WIN32_)
aot_set_last_error("emit object file on Windows is unsupported.");
goto fail;
@ -2751,7 +2865,9 @@ aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|| !aot_emit_relocation_section(buf, buf_end, &offset, comp_ctx,
comp_data, obj_data)
|| !aot_emit_native_symbol(buf, buf_end, &offset, comp_ctx)
|| !aot_emit_name_section(buf, buf_end, &offset, comp_data, comp_ctx))
|| !aot_emit_name_section(buf, buf_end, &offset, comp_data, comp_ctx)
|| !aot_emit_custom_sections(buf, buf_end, &offset, comp_data,
comp_ctx))
goto fail2;
#if 0

View File

@ -1587,6 +1587,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
comp_ctx->opt_level = option->opt_level;
comp_ctx->size_level = option->size_level;
comp_ctx->custom_sections_wp = option->custom_sections;
comp_ctx->custom_sections_count = option->custom_sections_count;
if (option->is_jit_mode) {
char *triple_jit = NULL;
@ -1657,6 +1660,51 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
opt_level = option->opt_level;
size_level = option->size_level;
/* verify external llc compiler */
comp_ctx->external_llc_compiler = getenv("WAMRC_LLC_COMPILER");
if (comp_ctx->external_llc_compiler) {
#if defined(_WIN32) || defined(_WIN32_)
comp_ctx->external_llc_compiler = NULL;
LOG_WARNING("External LLC compiler not supported on Windows.");
#else
if (access(comp_ctx->external_llc_compiler, X_OK) != 0) {
LOG_WARNING("WAMRC_LLC_COMPILER [%s] not found, fallback to "
"default pipeline",
comp_ctx->external_llc_compiler);
comp_ctx->external_llc_compiler = NULL;
}
else {
comp_ctx->llc_compiler_flags = getenv("WAMRC_LLC_FLAGS");
LOG_VERBOSE("Using external LLC compiler [%s]",
comp_ctx->external_llc_compiler);
}
#endif
}
/* verify external asm compiler */
if (!comp_ctx->external_llc_compiler) {
comp_ctx->external_asm_compiler = getenv("WAMRC_ASM_COMPILER");
if (comp_ctx->external_asm_compiler) {
#if defined(_WIN32) || defined(_WIN32_)
comp_ctx->external_asm_compiler = NULL;
LOG_WARNING("External ASM compiler not supported on Windows.");
#else
if (access(comp_ctx->external_asm_compiler, X_OK) != 0) {
LOG_WARNING(
"WAMRC_ASM_COMPILER [%s] not found, fallback to "
"default pipeline",
comp_ctx->external_asm_compiler);
comp_ctx->external_asm_compiler = NULL;
}
else {
comp_ctx->asm_compiler_flags = getenv("WAMRC_ASM_FLAGS");
LOG_VERBOSE("Using external ASM compiler [%s]",
comp_ctx->external_asm_compiler);
}
#endif
}
}
if (arch) {
/* Add default sub-arch if not specified */
if (!strcmp(arch, "arm"))

View File

@ -14,6 +14,7 @@
#include "llvm-c/Object.h"
#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Analysis.h"
#include "llvm-c/BitWriter.h"
#include "llvm-c/Transforms/Utils.h"
#include "llvm-c/Transforms/Scalar.h"
#include "llvm-c/Transforms/Vectorize.h"
@ -348,6 +349,22 @@ typedef struct AOTCompContext {
/* Function contexts */
AOTFuncContext **func_ctxes;
uint32 func_ctx_count;
char **custom_sections_wp;
uint32 custom_sections_count;
/* 3rd-party toolchains */
/* External llc compiler, if specified, wamrc will emit the llvm-ir file and
* invoke the llc compiler to generate object file.
* This can be used when we want to benefit from the optimization of other
* LLVM based toolchains */
const char *external_llc_compiler;
const char *llc_compiler_flags;
/* External asm compiler, if specified, wamrc will emit the text-based
* assembly file (.s) and invoke the llc compiler to generate object file.
* This will be useful when the upstream LLVM doesn't support to emit object
* file for some architecture (such as arc) */
const char *external_asm_compiler;
const char *asm_compiler_flags;
} AOTCompContext;
enum {
@ -378,6 +395,8 @@ typedef struct AOTCompOption {
uint32 size_level;
uint32 output_format;
uint32 bounds_checks;
char **custom_sections;
uint32 custom_sections_count;
} AOTCompOption, *aot_comp_option_t;
AOTCompContext *

View File

@ -59,6 +59,8 @@ typedef struct AOTCompOption {
uint32_t size_level;
uint32_t output_format;
uint32_t bounds_checks;
char **custom_sections;
uint32_t custom_sections_count;
} AOTCompOption, *aot_comp_option_t;
aot_comp_context_t

View File

@ -133,11 +133,12 @@ typedef struct RuntimeInitArgs {
/* maximum thread number, only used when
WASM_ENABLE_THREAD_MGR is defined */
uint32_t max_thread_num;
#if WASM_ENABLE_DEBUG_INTERP != 0
/* Debug settings, only used when
WASM_ENABLE_DEBUG_INTERP != 0 */
char ip_addr[128];
int platform_port;
int instance_port;
#endif
} RuntimeInitArgs;
#ifndef WASM_VALKIND_T_DEFINED
@ -406,6 +407,54 @@ WASM_RUNTIME_API_EXTERN wasm_function_inst_t
wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
const char *name, const char *signature);
/**
* Get parameter count of the function instance
*
* @param func_inst the function instance
* @param module_inst the module instance the function instance belongs to
*
* @return the parameter count of the function instance
*/
WASM_RUNTIME_API_EXTERN uint32_t
wasm_func_get_param_count(wasm_function_inst_t const func_inst,
wasm_module_inst_t const module_inst);
/**
* Get result count of the function instance
*
* @param func_inst the function instance
* @param module_inst the module instance the function instance belongs to
*
* @return the result count of the function instance
*/
WASM_RUNTIME_API_EXTERN uint32_t
wasm_func_get_result_count(wasm_function_inst_t const func_inst,
wasm_module_inst_t const module_inst);
/**
* Get parameter types of the function instance
*
* @param func_inst the function instance
* @param module_inst the module instance the function instance belongs to
* @param param_types the parameter types returned
*/
WASM_RUNTIME_API_EXTERN void
wasm_func_get_param_types(wasm_function_inst_t const func_inst,
wasm_module_inst_t const module_inst,
wasm_valkind_t *param_types);
/**
* Get result types of the function instance
*
* @param func_inst the function instance
* @param module_inst the module instance the function instance belongs to
* @param result_types the result types returned
*/
WASM_RUNTIME_API_EXTERN void
wasm_func_get_result_types(wasm_function_inst_t const func_inst,
wasm_module_inst_t const module_inst,
wasm_valkind_t *result_types);
/**
* Create execution environment for a WASM module instance.
*
@ -448,7 +497,7 @@ WASM_RUNTIME_API_EXTERN uint32_t
wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env);
/**
* Initialize thread environment.
* Initialize the thread environment.
* Note:
* If developer creates a child thread by himself to call the
* the wasm function in that thread, he should call this API
@ -463,11 +512,17 @@ WASM_RUNTIME_API_EXTERN bool
wasm_runtime_init_thread_env(void);
/**
* Destroy thread environment
* Destroy the thread environment
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_destroy_thread_env(void);
/**
* Whether the thread environment is initialized
*/
WASM_RUNTIME_API_EXTERN bool
wasm_runtime_thread_env_inited(void);
/**
* Get WASM module instance from execution environment
*
@ -998,6 +1053,20 @@ wasm_externref_retain(uint32_t externref_idx);
WASM_RUNTIME_API_EXTERN void
wasm_runtime_dump_call_stack(wasm_exec_env_t exec_env);
/**
* Get a custom section by name
*
* @param module_comm the module to find
* @param name name of the custom section
* @param len return the length of the content if found
*
* @return Custom section content (not including the name length
* and name string) if found, NULL otherwise
*/
WASM_RUNTIME_API_EXTERN const uint8_t *
wasm_runtime_get_custom_section(wasm_module_t const module_comm,
const char *name, uint32_t *len);
/* clang-format on */
#ifdef __cplusplus

View File

@ -346,6 +346,19 @@ typedef struct WASMFastOPCodeNode {
} WASMFastOPCodeNode;
#endif
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
typedef struct WASMCustomSection {
struct WASMCustomSection *next;
/* Start address of the section name */
char *name_addr;
/* Length of the section name decoded from leb */
uint32 name_len;
/* Start address of the content (name len and name skipped) */
uint8 *content_addr;
uint32 content_len;
} WASMCustomSection;
#endif
struct WASMModule {
/* Module type, for module loaded from WASM bytecode binary,
this field is Wasm_Module_Bytecode;
@ -468,6 +481,10 @@ struct WASMModule {
const uint8 *name_section_buf_end;
#endif
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
WASMCustomSection *custom_section_list;
#endif
#if WASM_ENABLE_FAST_JIT != 0
/* point to JITed functions */
void **fast_jit_func_ptrs;

View File

@ -14,6 +14,7 @@
#endif
#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
#include "../libraries/thread-mgr/thread_manager.h"
#include "../libraries/debug-engine/debug_engine.h"
#endif
#if WASM_ENABLE_FAST_JIT != 0
#include "../fast-jit/jit_compiler.h"
@ -947,6 +948,9 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
#define HANDLE_OP_END() \
do { \
/* Record the current frame_ip, so when exception occurs, \
debugger can know the exact opcode who caused the exception */ \
frame_ip_orig = frame_ip; \
while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
&& exec_env->current_status->step_count++ == 1) { \
exec_env->current_status->step_count = 0; \
@ -1024,6 +1028,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 cache_index, type_index, param_cell_num, cell_num;
uint8 value_type;
#if WASM_ENABLE_DEBUG_INTERP != 0
uint8 *frame_ip_orig = NULL;
#endif
#if WASM_ENABLE_LABELS_AS_VALUES != 0
#define HANDLE_OPCODE(op) &&HANDLE_##op
DEFINE_GOTO_TABLE(const void *, handle_table);
@ -3751,6 +3759,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
wasm_set_exception(module, "out of bounds memory access");
got_exception:
#if WASM_ENABLE_DEBUG_INTERP != 0
if (wasm_exec_env_get_instance(exec_env) != NULL) {
uint8 *frame_ip_temp = frame_ip;
frame_ip = frame_ip_orig;
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP);
CHECK_SUSPEND_FLAGS();
frame_ip = frame_ip_temp;
}
#endif
SYNC_ALL_TO_FRAME();
return;

View File

@ -2815,7 +2815,8 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
uint32 error_buf_size)
{
const uint8 *p = buf, *p_end = buf_end;
uint32 name_len;
char section_name[32];
uint32 name_len, buffer_len;
if (p >= p_end) {
set_error_buf(error_buf, error_buf_size, "unexpected end");
@ -2834,6 +2835,16 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
return false;
}
buffer_len = sizeof(section_name);
memset(section_name, 0, buffer_len);
if (name_len < buffer_len) {
bh_memcpy_s(section_name, buffer_len, p, name_len);
}
else {
bh_memcpy_s(section_name, buffer_len, p, buffer_len - 4);
memset(section_name + buffer_len - 4, '.', 3);
}
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
if (memcmp(p, "name", 4) == 0) {
module->name_section_buf = buf;
@ -2841,9 +2852,34 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
p += name_len;
handle_name_section(p, p_end, module, is_load_from_file_buf, error_buf,
error_buf_size);
LOG_VERBOSE("Load custom name section success.");
return true;
}
#endif
LOG_VERBOSE("Load custom section success.\n");
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
{
WASMCustomSection *section =
loader_malloc(sizeof(WASMCustomSection), error_buf, error_buf_size);
if (!section) {
return false;
}
section->name_addr = (char *)p;
section->name_len = name_len;
section->content_addr = (uint8 *)(p + name_len);
section->content_len = p_end - p - name_len;
section->next = module->custom_section_list;
module->custom_section_list = section;
LOG_VERBOSE("Load custom section [%s] success.", section_name);
return true;
}
#endif
LOG_VERBOSE("Ignore custom section [%s].", section_name);
return true;
fail:
return false;
@ -3792,6 +3828,10 @@ wasm_loader_unload(WASMModule *module)
os_mutex_destroy(&module->ref_count_lock);
#endif
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
wasm_runtime_destroy_custom_sections(module->custom_section_list);
#endif
#if WASM_ENABLE_FAST_JIT != 0
if (module->fast_jit_func_ptrs) {
for (i = 0; i < module->function_count; i++) {
@ -6493,6 +6533,29 @@ get_table_seg_elem_type(const WASMModule *module, uint32 table_seg_idx,
}
#endif
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
const uint8 *
wasm_loader_get_custom_section(WASMModule *module, const char *name,
uint32 *len)
{
WASMCustomSection *section = module->custom_section_list;
while (section) {
if ((section->name_len == strlen(name))
&& (memcmp(section->name_addr, name, section->name_len) == 0)) {
if (len) {
*len = section->content_len;
}
return section->content_addr;
}
section = section->next;
}
return false;
}
#endif
static bool
wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
uint32 cur_func_idx, char *error_buf,
@ -6540,6 +6603,16 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
}
#if WASM_ENABLE_FAST_INTERP != 0
/* For the first traverse, the initial value of preserved_local_offset has
* not been determined, we use the INT16_MAX to represent that a slot has
* been copied to preserve space. For second traverse, this field will be
* set to the appropriate value in wasm_loader_ctx_reinit.
* This is for Issue #1230,
* https://github.com/bytecodealliance/wasm-micro-runtime/issues/1230, the
* drop opcodes need to know which slots are preserved, so those slots will
* not be treated as dynamically allocated slots */
loader_ctx->preserved_local_offset = INT16_MAX;
re_scan:
if (loader_ctx->code_compiled_size > 0) {
if (!wasm_loader_ctx_reinit(loader_ctx)) {
@ -7197,8 +7270,10 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
skip_label();
loader_ctx->frame_offset--;
if (*(loader_ctx->frame_offset)
> loader_ctx->start_dynamic_offset)
if ((*(loader_ctx->frame_offset)
> loader_ctx->start_dynamic_offset)
&& (*(loader_ctx->frame_offset)
< loader_ctx->max_dynamic_offset))
loader_ctx->dynamic_offset--;
#endif
}
@ -7211,8 +7286,10 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
skip_label();
loader_ctx->frame_offset -= 2;
if (*(loader_ctx->frame_offset)
> loader_ctx->start_dynamic_offset)
if ((*(loader_ctx->frame_offset)
> loader_ctx->start_dynamic_offset)
&& (*(loader_ctx->frame_offset)
< loader_ctx->max_dynamic_offset))
loader_ctx->dynamic_offset -= 2;
#endif
}

View File

@ -4901,6 +4901,16 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
}
#if WASM_ENABLE_FAST_INTERP != 0
/* For the first traverse, the initial value of preserved_local_offset has
* not been determined, we use the INT16_MAX to represent that a slot has
* been copied to preserve space. For second traverse, this field will be
* set to the appropriate value in wasm_loader_ctx_reinit.
* This is for Issue #1230,
* https://github.com/bytecodealliance/wasm-micro-runtime/issues/1230, the
* drop opcodes need to know which slots are preserved, so those slots will
* not be treated as dynamically allocated slots */
loader_ctx->preserved_local_offset = INT16_MAX;
re_scan:
if (loader_ctx->code_compiled_size > 0) {
if (!wasm_loader_ctx_reinit(loader_ctx)) {
@ -5477,8 +5487,10 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
skip_label();
loader_ctx->frame_offset--;
if (*(loader_ctx->frame_offset)
> loader_ctx->start_dynamic_offset)
if ((*(loader_ctx->frame_offset)
> loader_ctx->start_dynamic_offset)
&& (*(loader_ctx->frame_offset)
< loader_ctx->max_dynamic_offset))
loader_ctx->dynamic_offset--;
#endif
}
@ -5491,8 +5503,10 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
skip_label();
loader_ctx->frame_offset -= 2;
if (*(loader_ctx->frame_offset)
> loader_ctx->start_dynamic_offset)
if ((*(loader_ctx->frame_offset)
> loader_ctx->start_dynamic_offset)
&& (*(loader_ctx->frame_offset)
< loader_ctx->max_dynamic_offset))
loader_ctx->dynamic_offset -= 2;
#endif
}

View File

@ -1935,8 +1935,8 @@ wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size,
}
if (memory->heap_handle) {
addr = mem_allocator_realloc(memory->heap_handle,
memory->memory_data + ptr, size);
addr = mem_allocator_realloc(
memory->heap_handle, ptr ? memory->memory_data + ptr : NULL, size);
}
/* Only support realloc in WAMR's app heap */

View File

@ -458,6 +458,10 @@ void
wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env);
#endif
const uint8 *
wasm_loader_get_custom_section(WASMModule *module, const char *name,
uint32 *len);
#ifdef __cplusplus
}
#endif

View File

@ -456,7 +456,7 @@ wasm_debug_instance_destroy(WASMCluster *cluster)
}
}
static WASMExecEnv *
WASMExecEnv *
wasm_debug_instance_get_current_env(WASMDebugInstance *instance)
{
WASMExecEnv *exec_env = NULL;
@ -829,7 +829,10 @@ WASMDebugInstance *
wasm_exec_env_get_instance(WASMExecEnv *exec_env)
{
WASMDebugInstance *instance = NULL;
bh_assert(g_debug_engine);
if (!g_debug_engine) {
return NULL;
}
os_mutex_lock(&g_debug_engine->instance_list_lock);
instance = bh_list_first_elem(&g_debug_engine->debug_instance_list);

View File

@ -128,6 +128,9 @@ wasm_debug_set_engine_active(bool active);
bool
wasm_debug_get_engine_active(void);
WASMExecEnv *
wasm_debug_instance_get_current_env(WASMDebugInstance *instance);
uint64
wasm_debug_instance_get_pid(WASMDebugInstance *instance);

View File

@ -334,6 +334,8 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
char pc_string[17];
uint32 tids_count, i = 0;
uint32 gdb_status = status;
WASMExecEnv *exec_env;
const char *exception;
if (status == 0) {
os_mutex_lock(&tmpbuf_lock);
@ -370,20 +372,43 @@ send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
mem2hex((void *)&pc, pc_string, 8);
pc_string[8 * 2] = '\0';
if (status == WAMR_SIG_TRAP) {
len += snprintf(tmpbuf + len, sizeof(tmpbuf) - len,
"thread-pcs:%" PRIx64 ";00:%s,reason:%s;", pc,
pc_string, "breakpoint");
exec_env = wasm_debug_instance_get_current_env(
(WASMDebugInstance *)server->thread->debug_instance);
bh_assert(exec_env);
exception =
wasm_runtime_get_exception(wasm_runtime_get_module_inst(exec_env));
if (exception) {
/* When exception occurs, use reason:exception so the description can be
* correctly processed by LLDB */
uint32 exception_len = strlen(exception);
len +=
snprintf(tmpbuf + len, sizeof(tmpbuf) - len,
"thread-pcs:%" PRIx64 ";00:%s;reason:%s;description:", pc,
pc_string, "exception");
/* The description should be encoded as HEX */
for (i = 0; i < exception_len; i++) {
len += snprintf(tmpbuf + len, sizeof(tmpbuf) - len, "%02x",
exception[i]);
}
len += snprintf(tmpbuf + len, sizeof(tmpbuf) - len, ";");
}
else if (status == WAMR_SIG_SINGSTEP) {
len += snprintf(tmpbuf + len, sizeof(tmpbuf) - len,
"thread-pcs:%" PRIx64 ";00:%s,reason:%s;", pc,
pc_string, "trace");
}
else if (status > 0) {
len += snprintf(tmpbuf + len, sizeof(tmpbuf) - len,
"thread-pcs:%" PRIx64 ";00:%s,reason:%s;", pc,
pc_string, "signal");
else {
if (status == WAMR_SIG_TRAP) {
len += snprintf(tmpbuf + len, sizeof(tmpbuf) - len,
"thread-pcs:%" PRIx64 ";00:%s;reason:%s;", pc,
pc_string, "breakpoint");
}
else if (status == WAMR_SIG_SINGSTEP) {
len += snprintf(tmpbuf + len, sizeof(tmpbuf) - len,
"thread-pcs:%" PRIx64 ";00:%s;reason:%s;", pc,
pc_string, "trace");
}
else if (status > 0) {
len += snprintf(tmpbuf + len, sizeof(tmpbuf) - len,
"thread-pcs:%" PRIx64 ";00:%s;reason:%s;", pc,
pc_string, "signal");
}
}
write_packet(server, tmpbuf);
os_mutex_unlock(&tmpbuf_lock);

View File

@ -1091,7 +1091,7 @@ static float
freebsd_fminf(float x, float y)
{
if (is_little_endian()) {
IEEEf2bits_L u[2];
IEEEf2bits_L u[2] = { 0 };
u[0].f = x;
u[1].f = y;
@ -1107,7 +1107,7 @@ freebsd_fminf(float x, float y)
return (u[u[1].bits.sign].f);
}
else {
IEEEf2bits_B u[2];
IEEEf2bits_B u[2] = { 0 };
u[0].f = x;
u[1].f = y;
@ -1130,7 +1130,7 @@ static float
freebsd_fmaxf(float x, float y)
{
if (is_little_endian()) {
IEEEf2bits_L u[2];
IEEEf2bits_L u[2] = { 0 };
u[0].f = x;
u[1].f = y;
@ -1146,7 +1146,7 @@ freebsd_fmaxf(float x, float y)
return (u[u[0].bits.sign].f);
}
else {
IEEEf2bits_B u[2];
IEEEf2bits_B u[2] = { 0 };
u[0].f = x;
u[1].f = y;

View File

@ -107,6 +107,12 @@ os_thread_env_init();
void
os_thread_env_destroy();
/**
* Whether the thread environment is initialized
*/
bool
os_thread_env_inited();
/**
* Suspend execution of the calling thread for (at least)
* usec microseconds

View File

@ -28,6 +28,7 @@
#include "sgx_time.h"
#include "sgx_socket.h"
#include "sgx_signal.h"
#include "sgx_trts.h"
#ifdef __cplusplus
extern "C" {

View File

@ -116,10 +116,6 @@ int
ocall_getopt(int *p_ret, int argc, char *argv_buf, unsigned int argv_buf_len,
const char *optstring);
int
ocall_getrandom(ssize_t *p_ret, void *buf, size_t buflen, unsigned int flags);
int
ocall_getentropy(int *p_ret, void *buffer, size_t length);
int
ocall_sched_yield(int *p_ret);
/** struct iovec **/
@ -891,29 +887,124 @@ sched_yield(void)
ssize_t
getrandom(void *buf, size_t buflen, unsigned int flags)
{
ssize_t ret;
sgx_status_t ret;
if (ocall_getrandom(&ret, buf, buflen, flags) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
if (!buf || buflen > INT32_MAX || flags != 0) {
errno = EINVAL;
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
ret = sgx_read_rand(buf, buflen);
if (ret != SGX_SUCCESS) {
errno = EFAULT;
return -1;
}
return (ssize_t)buflen;
}
#define RDRAND_RETRIES 3
static int
rdrand64_step(uint64 *seed)
{
uint8 ok;
__asm__ volatile("rdseed %0; setc %1" : "=r"(*seed), "=qm"(ok));
return (int)ok;
}
static int
rdrand64_retry(uint64 *rand, uint32 retries)
{
uint32 count = 0;
while (count++ <= retries) {
if (rdrand64_step(rand)) {
return -1;
}
}
return 0;
}
static uint32
rdrand_get_bytes(uint8 *dest, uint32 n)
{
uint8 *head_start = dest, *tail_start = NULL;
uint64 *block_start;
uint32 count, ltail, lhead, lblock;
uint64 i, temp_rand;
/* Get the address of the first 64-bit aligned block in the
destination buffer. */
if (((uintptr_t)head_start & (uintptr_t)7) == 0) {
/* already 8-byte aligned */
block_start = (uint64 *)head_start;
lhead = 0;
lblock = n & ~7;
}
else {
/* next 8-byte aligned */
block_start = (uint64 *)(((uintptr_t)head_start + 7) & ~(uintptr_t)7);
lhead = (uint32)((uintptr_t)block_start - (uintptr_t)head_start);
lblock = (n - lhead) & ~7;
}
/* Compute the number of 64-bit blocks and the remaining number
of bytes (the tail) */
ltail = n - lblock - lhead;
if (ltail > 0) {
tail_start = (uint8 *)block_start + lblock;
}
/* Populate the starting, mis-aligned section (the head) */
if (lhead > 0) {
if (!rdrand64_retry(&temp_rand, RDRAND_RETRIES)) {
return 0;
}
memcpy(head_start, &temp_rand, lhead);
}
/* Populate the central, aligned blocks */
count = lblock / 8;
for (i = 0; i < count; i++, block_start++) {
if (!rdrand64_retry(block_start, RDRAND_RETRIES)) {
return i * 8 + lhead;
}
}
/* Populate the tail */
if (ltail > 0) {
if (!rdrand64_retry(&temp_rand, RDRAND_RETRIES)) {
return count * 8 + lhead;
}
memcpy(tail_start, &temp_rand, ltail);
}
return n;
}
int
getentropy(void *buffer, size_t length)
{
int ret;
uint32 size;
if (ocall_getentropy(&ret, buffer, length) != SGX_SUCCESS) {
TRACE_OCALL_FAIL();
if (!buffer || length > INT32_MAX) {
errno = EINVAL;
return -1;
}
if (ret == -1)
errno = get_errno();
return ret;
if (length == 0) {
return 0;
}
size = rdrand_get_bytes(buffer, (uint32)length);
if (size != length) {
errno = EFAULT;
return -1;
}
return 0;
}
int

View File

@ -250,6 +250,7 @@ sched_yield(void);
ssize_t
getrandom(void *buf, size_t buflen, unsigned int flags);
int
getentropy(void *buffer, size_t length);

View File

@ -77,9 +77,6 @@ enclave {
[in, size=argv_buf_len]char *argv_buf,
unsigned int argv_buf_len,
[in, string]const char *optstring);
ssize_t ocall_getrandom([out, size=buflen]void *buf, size_t buflen,
unsigned int flags);
int ocall_getentropy([out, size=length]void *buffer, size_t length);
ssize_t ocall_readv(int fd,
[in, out, size=buf_size]char *iov_buf,
unsigned int buf_size, int iovcnt,

View File

@ -10,7 +10,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/random.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
@ -303,18 +302,6 @@ ocall_getopt(int argc, char *argv_buf, unsigned int argv_buf_len,
return getopt(argc, argv, optstring);
}
ssize_t
ocall_getrandom(void *buf, size_t buflen, unsigned int flags)
{
return getrandom(buf, buflen, flags);
}
int
ocall_getentropy(void *buffer, size_t length)
{
return getentropy(buffer, length);
}
int
ocall_sched_yield()
{

View File

@ -6,6 +6,10 @@
#include "platform_api_extension.h"
#include "platform_api_vmcore.h"
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
#include <nuttx/arch.h>
#endif
int
bh_platform_init()
{
@ -37,6 +41,12 @@ os_free(void *ptr)
void *
os_mmap(void *hint, size_t size, int prot, int flags)
{
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
if ((prot & MMAP_PROT_EXEC) != 0) {
return up_textheap_memalign(sizeof(void *), size);
}
#endif
if ((uint64)size >= UINT32_MAX)
return NULL;
return malloc((uint32)size);
@ -45,6 +55,12 @@ os_mmap(void *hint, size_t size, int prot, int flags)
void
os_munmap(void *addr, size_t size)
{
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
if (up_textheap_heapmember(addr)) {
up_textheap_free(addr);
return;
}
#endif
return free(addr);
}
@ -57,3 +73,75 @@ os_mprotect(void *addr, size_t size, int prot)
void
os_dcache_flush()
{}
/* If AT_FDCWD is provided, maybe we have openat family */
#if !defined(AT_FDCWD)
int
openat(int fd, const char *path, int oflags, ...)
{
errno = ENOSYS;
return -1;
}
int
fstatat(int fd, const char *path, struct stat *buf, int flag)
{
errno = ENOSYS;
return -1;
}
int
mkdirat(int fd, const char *path, mode_t mode)
{
errno = ENOSYS;
return -1;
}
ssize_t
readlinkat(int fd, const char *path, char *buf, size_t bufsize)
{
errno = ENOSYS;
return -1;
}
int
linkat(int fd1, const char *path1, int fd2, const char *path2, int flag)
{
errno = ENOSYS;
return -1;
}
int
renameat(int fromfd, const char *from, int tofd, const char *to)
{
errno = ENOSYS;
return -1;
}
int
symlinkat(const char *target, int fd, const char *path)
{
errno = ENOSYS;
return -1;
}
int
unlinkat(int fd, const char *path, int flag)
{
errno = ENOSYS;
return -1;
}
int
utimensat(int fd, const char *path, const struct timespec ts[2], int flag)
{
errno = ENOSYS;
return -1;
}
#endif /* !defined(AT_FDCWD) */
DIR *
fdopendir(int fd)
{
errno = ENOSYS;
return NULL;
}

View File

@ -8,15 +8,21 @@
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <poll.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mman.h>
@ -50,6 +56,63 @@ typedef pthread_t korp_thread;
/* On NuttX, time_t is uint32_t */
#define BH_TIME_T_MAX 0xffffffff
/*
* NuttX doesn't have O_DIRECTORY or directory open.
* REVISIT: maybe this is safer to be disabled at higher level.
*/
#if !defined(O_DIRECTORY)
#define O_DIRECTORY 0
#endif
#if !defined(O_NOFOLLOW)
#define O_NOFOLLOW 0
#endif
#undef CONFIG_HAS_ISATTY
#ifdef CONFIG_SERIAL_TERMIOS
#define CONFIG_HAS_ISATTY 1
#else
#define CONFIG_HAS_ISATTY 0
#endif
/*
* NuttX doesn't have openat family.
*/
/* If AT_FDCWD is provided, maybe we have openat family */
#if !defined(AT_FDCWD)
int
openat(int fd, const char *path, int oflags, ...);
int
fstatat(int fd, const char *path, struct stat *buf, int flag);
int
mkdirat(int fd, const char *path, mode_t mode);
ssize_t
readlinkat(int fd, const char *path, char *buf, size_t bufsize);
int
linkat(int fd1, const char *path1, int fd2, const char *path2, int flag);
int
renameat(int fromfd, const char *from, int tofd, const char *to);
int
symlinkat(const char *target, int fd, const char *path);
int
unlinkat(int fd, const char *path, int flag);
int
utimensat(int fd, const char *path, const struct timespec ts[2], int flag);
#define AT_SYMLINK_NOFOLLOW 0
#define AT_SYMLINK_FOLLOW 0
#define AT_REMOVEDIR 0
#endif /* !defined(AT_FDCWD) */
/*
* NuttX doesn't have fdopendir.
*/
DIR *
fdopendir(int fd);
#ifdef __cplusplus
}
#endif

View File

@ -360,6 +360,13 @@ os_thread_env_destroy()
}
}
bool
os_thread_env_inited()
{
os_thread_data *thread_data = TlsGetValue(thread_data_key);
return thread_data ? true : false;
}
int
os_sem_init(korp_sem *sem)
{

View File

@ -23,6 +23,10 @@ alloc_vector_data(size_t length, size_t size_elem)
return data;
}
/**
* every caller of `extend_vector` must provide
* a thread-safe environment.
*/
static bool
extend_vector(Vector *vector, size_t length)
{
@ -38,15 +42,12 @@ extend_vector(Vector *vector, size_t length)
return false;
}
if (vector->lock)
os_mutex_lock(vector->lock);
memcpy(data, vector->data, vector->size_elem * vector->max_elems);
bh_memcpy_s(data, vector->size_elem * length, vector->data,
vector->size_elem * vector->max_elems);
BH_FREE(vector->data);
vector->data = data;
vector->max_elems = length;
if (vector->lock)
os_mutex_unlock(vector->lock);
return true;
}
@ -109,8 +110,8 @@ bh_vector_set(Vector *vector, uint32 index, const void *elem_buf)
if (vector->lock)
os_mutex_lock(vector->lock);
memcpy(vector->data + vector->size_elem * index, elem_buf,
vector->size_elem);
bh_memcpy_s(vector->data + vector->size_elem * index, vector->size_elem,
elem_buf, vector->size_elem);
if (vector->lock)
os_mutex_unlock(vector->lock);
return true;
@ -131,8 +132,8 @@ bh_vector_get(Vector *vector, uint32 index, void *elem_buf)
if (vector->lock)
os_mutex_lock(vector->lock);
memcpy(elem_buf, vector->data + vector->size_elem * index,
vector->size_elem);
bh_memcpy_s(elem_buf, vector->size_elem,
vector->data + vector->size_elem * index, vector->size_elem);
if (vector->lock)
os_mutex_unlock(vector->lock);
return true;
@ -143,58 +144,73 @@ bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf)
{
size_t i;
uint8 *p;
bool ret = false;
if (!vector || !elem_buf) {
LOG_ERROR("Insert vector elem failed: vector or elem buf is NULL.\n");
return false;
goto just_return;
}
if (index >= vector->num_elems) {
LOG_ERROR("Insert vector elem failed: invalid elem index.\n");
return false;
}
if (!extend_vector(vector, vector->num_elems + 1)) {
LOG_ERROR("Insert vector elem failed: extend vector failed.\n");
return false;
goto just_return;
}
if (vector->lock)
os_mutex_lock(vector->lock);
if (!extend_vector(vector, vector->num_elems + 1)) {
LOG_ERROR("Insert vector elem failed: extend vector failed.\n");
goto unlock_return;
}
p = vector->data + vector->size_elem * vector->num_elems;
for (i = vector->num_elems - 1; i > index; i--) {
memcpy(p, p - vector->size_elem, vector->size_elem);
bh_memcpy_s(p, vector->size_elem, p - vector->size_elem,
vector->size_elem);
p -= vector->size_elem;
}
memcpy(p, elem_buf, vector->size_elem);
bh_memcpy_s(p, vector->size_elem, elem_buf, vector->size_elem);
vector->num_elems++;
ret = true;
unlock_return:
if (vector->lock)
os_mutex_unlock(vector->lock);
return true;
just_return:
return ret;
}
bool
bh_vector_append(Vector *vector, const void *elem_buf)
{
bool ret = false;
if (!vector || !elem_buf) {
LOG_ERROR("Append vector elem failed: vector or elem buf is NULL.\n");
return false;
goto just_return;
}
/* make sure one more slot is used by the thread who allocas it */
if (vector->lock)
os_mutex_lock(vector->lock);
if (!extend_vector(vector, vector->num_elems + 1)) {
LOG_ERROR("Append ector elem failed: extend vector failed.\n");
return false;
goto unlock_return;
}
if (vector->lock)
os_mutex_lock(vector->lock);
memcpy(vector->data + vector->size_elem * vector->num_elems, elem_buf,
vector->size_elem);
bh_memcpy_s(vector->data + vector->size_elem * vector->num_elems,
vector->size_elem, elem_buf, vector->size_elem);
vector->num_elems++;
ret = true;
unlock_return:
if (vector->lock)
os_mutex_unlock(vector->lock);
return true;
just_return:
return ret;
}
bool
@ -218,11 +234,12 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf)
p = vector->data + vector->size_elem * index;
if (old_elem_buf) {
memcpy(old_elem_buf, p, vector->size_elem);
bh_memcpy_s(old_elem_buf, vector->size_elem, p, vector->size_elem);
}
for (i = index; i < vector->num_elems - 1; i++) {
memcpy(p, p + vector->size_elem, vector->size_elem);
bh_memcpy_s(p, vector->size_elem, p + vector->size_elem,
vector->size_elem);
p += vector->size_elem;
}

View File

@ -148,6 +148,15 @@ Currently we only profile the memory consumption of module, module_instance and
- **WAMR_BUILD_DEBUG_INTERP**=1/0, default to 0 if not set
> Note: There are some other setup required by source debugging, please refer to [source_debugging.md](./source_debugging.md) for more details.
#### **Enable load wasm custom sections**
- **WAMR_BUILD_LOAD_CUSTOM_SECTION**=1/0, default to disable if not set
> Note: By default, the custom sections are ignored. If the embedder wants to get custom sections from `wasm_module_t`, then `WAMR_BUILD_LOAD_CUSTOM_SECTION` should be enabled, and then `wasm_runtime_get_custom_section` can be used to get a custom section by name.
> Note: If `WAMR_BUILD_CUSTOM_NAME_SECTION` is enabled, then the `custom name section` will be treated as a special section and consumed by the runtime, not available to the embedder.
> For AoT file, must use `--emit-custom-sections` to specify which sections need to be emitted into AoT file, otherwise all custom sections (except custom name section) will be ignored.
**Combination of configurations:**
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:
@ -216,7 +225,7 @@ To run an AOT file, firstly please refer to [Build wamrc AOT compiler](../README
wamrc -o <AOT file> <WASM file>
iwasm <AOT file>
```
To enable the `JIT` mode, firstly we should build LLVM:
``` Bash
@ -246,7 +255,7 @@ cd build
cmake .. -DWAMR_BUILD_FAST_INTERP=0
make
```
Linux SGX (Intel Software Guard Extension)
-------------------------
@ -546,14 +555,14 @@ WAMR is intergrated with NuttX, just enable the WAMR in Kconfig option (Applicat
ESP-IDF
-------------------------
WAMR integrates with ESP-IDF both for the XTENSA and RISC-V chips (esp32x and esp32c3 respectively).
WAMR integrates with ESP-IDF both for the XTENSA and RISC-V chips (esp32x and esp32c3 respectively).
In order to use this, you need at least version 4.3.1 of ESP-IDF.
If you don't have it installed, follow the instructions [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/#get-started-get-prerequisites).
ESP-IDF also installs the toolchains needed for compiling WAMR and ESP-IDF.
A small demonstration of how to use WAMR and ESP-IDF can be found under [product_mini](/product-mini/platforms/esp-idf).
The demo builds WAMR for ESP-IDF and runs a small wasm program.
In order to run it for your specific Espressif chip, edit the ['build.sh'](/product-mini/platforms/esp-idf/build.sh) file and put the correct toolchain file (see #Cross-compilation) and `IDF_TARGET`.
The demo builds WAMR for ESP-IDF and runs a small wasm program.
In order to run it for your specific Espressif chip, edit the ['build_and_run.sh'](/product-mini/platforms/esp-idf/build_and_run.sh) file and put the correct toolchain file (see #Cross-compilation) and `IDF_TARGET`.
Before compiling it is also necessary to call ESP-IDF's `export.sh` script to bring all compile time relevant information in scope.
Docker

View File

@ -330,6 +330,36 @@ Examples: wamrc -o test.aot test.wasm
wamrc --target=i386 --format=object -o test.o test.wasm
```
## AoT compilation with 3rd-party toolchains
`wamrc` uses LLVM to compile wasm bytecode to AoT file, this works for most of the architectures, but there may be circumstances where you want to use 3rd-party toolchains to take over some steps of the compilation pipeline, e.g.
1. The upstream LLVM doesn't support generating object file for your CPU architecture (such as ARC), then we may need some other assembler to do such things.
2. You may get some other LLVM-based toolchains which may have better optimizations for the specific target, then you may want your toolchain to take over all optimization steps.
`wamrc` provides two environment variables to achieve these:
- `WAMRC_LLC_COMPILER`
When specified, `wamrc` will emit the optimized LLVM-IR (.bc) to a file, and invoke `$WAMRC_LLC_COMPILER` with ` -c -O3 ` to generate the object file.
Optionally, you can use environment variable `WAMRC_LLC_FLAGS` to overwrite the default flags.
- `WAMRC_ASM_COMPILER`
When specified, `wamrc` will emit the text based assembly file (.s), and invoke `$WAMRC_ASM_COMPILER` with ` -c -O3 ` to generate the object file.
Optionally, you can use environment variable `WAMRC_ASM_FLAGS` to overwrite the default flags.
### Usage example
``` bash
WAMRC_LLC_COMPILER=<path/to/your/compiler/driver> ./wamrc -o test.aot test.wasm
```
> Note: `wamrc` will verify whether the specified file exists and executable. If verification failed, `wamrc` will report a warning and fallback to normal pipeline. Since the verification is based on file, you **must specify the absolute path to the binary** even if it's in `$PATH`
> Note: `WAMRC_LLC_COMPILER` has higher priority than `WAMRC_ASM_COMPILER`, if `WAMRC_LLC_COMPILER` is set and verified, then `WAMRC_ASM_COMPILER` will be ignored.
> Note: the `LLC` and `ASM` in the env name just means this compiler will be used to compile the `LLVM IR file`/`assembly file` to object file, usually passing the compiler driver is the simplest way. (e.g. for LLVM toolchain, you don't need to pass `/usr/bin/llc`, using `/usr/bin/clang` is OK)
Run WASM app in WAMR mini product build
=======================================

View File

@ -1,7 +1,9 @@
Embedding WAMR guideline
=====================================
**Note**: All the embedding APIs supported by the runtime are defined under folder [core/iwasm/include](../core/iwasm/include). The API details are available in the header files.
**Note**: This document is about how to embed WAMR into C/C++ host applications, for other languages, please refer to: [Embed WAMR into Python](../language-bindings/go), [Embed WAMR into Go](../language-bindings/go).
All the embedding APIs supported by the runtime are defined under folder [core/iwasm/include](../core/iwasm/include). The API details are available in the header files.
## Embed WAMR into developer's project
@ -109,7 +111,7 @@ There are several ways to call WASM function:
1. Function call with parameters in an array of 32 bits elements and size:
```c
unit32 argv[2];
uint32 argv[2];
/* arguments are always transferred in 32-bit element */
argv[0] = 8;
@ -128,11 +130,11 @@ There are several ways to call WASM function:
The parameters are transferred in an array of 32 bits elements. For parameters that occupy 4 or fewer bytes, each parameter can be a single array element. For parameters in types like double or int64, each parameter will take two array elements. The function return value will be sent back in the first one or two elements of the array according to the value type. See the sample code below:
```c
unit32 argv[6];
uint32 argv[6];
char arg1 = 'a';
int arg2 = 10;
double arg3 = 1.0;
int 64 arg4 = 100;
int64 arg4 = 100;
double ret;
argv[0] = arg1;
@ -160,7 +162,7 @@ The parameters are transferred in an array of 32 bits elements. For parameters t
2. Function call with results and arguments both in `wasm_val_t` struct and size:
```c
unit32 num_args = 1, num_results = 1;
uint32 num_args = 1, num_results = 1;
wasm_val_t args[1], results[1];
/* set the argument type and value */
@ -181,7 +183,7 @@ The parameters are transferred in an array of 32 bits elements. For parameters t
3. Function call with variant argument support:
```c
unit32 num_args = 1, num_results = 1;
uint32 num_args = 1, num_results = 1;
wasm_val_t results[1];
/* call the WASM function */
@ -238,7 +240,7 @@ uint32_t buffer_for_wasm;
buffer_for_wasm = wasm_runtime_module_malloc(module_inst, 100, &buffer);
if (buffer_for_wasm != 0) {
unit32 argv[2];
uint32 argv[2];
strncpy(buffer, "hello", 100); /* use native address for accessing in runtime */
argv[0] = buffer_for_wasm; /* pass the buffer address for WASM space */
argv[1] = 100; /* the size of buffer */

View File

@ -0,0 +1,104 @@
WAMR Go binding: Embedding WAMR in Go guideline
===============================================
This Go library uses CGO to consume the runtime APIs of the WAMR project which are defined in [core/iwasm/include/wasm_export.h](../../core/iwasm/include/wasm_export.h). The API details are available in the header files.
## Installation
### Installing from the source code
Installing from local source tree is in _development mode_.
Run `./build.sh` in this folder to build the package, which builds the WAMR runtime library firstly and then builds the Go binding library.
Run `./build.sh` under `samples` folder to build and test the sample.
```bash
cd samples
./build.sh
```
## Supported APIs
All the embedding APIs supported are defined under folder [wamr](./wamr).
### Runtime APIs
```Go
func Runtime() *_Runtime
func (self *_Runtime) FullInit(alloc_with_pool bool, heap_buf []byte,
max_thread_num uint) error
func (self *_Runtime) Init() error
func (self *_Runtime) Destroy()
func (self *_Runtime) SetLogLevel(level LogLevel)
func (self *_Runtime) Malloc(size uint32) *uint8
func (self *_Runtime) Free(ptr *uint8)
```
### Module APIs
```Go
func NewModule(wasmBytes []byte) (*Module, error)
func (self *Module) Destroy()
func (self *Module) SetWasiArgs(dirList [][]byte, mapDirList [][]byte,
env [][]byte, argv[][]byte)
func (self *Module) SetWasiArgsEx(dirList [][]byte, mapDirList [][]byte,
env [][]byte, argv[][]byte,
stdinfd int, stdoutfd int, stderrfd int)
func (self *Module) SetWasiAddrPool(addrPool [][]byte)
```
### Instance APIs
```Go
func NewInstance(module *Module,
stackSize uint, heapSize uint) (*Instance, error)
func (self *Instance) Destroy()
func (self *Instance) CallFunc(funcName string,
argc uint32, args []uint32) error
func (self *Instance) CallFuncV(funcName string,
num_results uint32, results []interface{},
args ... interface{}) error
func (self *Instance) GetException() string
func (self Instance) ModuleMalloc(size uint32) (uint32, *uint8)
func (self Instance) ModuleFree(offset uint32)
func (self Instance) ValidateAppAddr(app_offset uint32, size uint32) bool
func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint32) bool
func (self Instance) AddrAppToNative(app_offset uint32) *uint8
func (self Instance) AddrNativeToApp(native_ptr *uint8) uint32
func (self Instance) GetAppAddrRange(app_offset uint32) (bool, uint32, uint32)
func (self Instance) GetNativeAddrRange(native_ptr *uint8) (bool, *uint8, *uint8)
func (self Instance) DumpMemoryConsumption()
func (self Instance) DumpCallStack()
```
## Sample codes
```Go
var module *wamr.Module
var instance *wamr.Instance
var results []interface{}
var err error
/* Runtime initialization */
err = wamr.Runtime().FullInit(false, nil, 1)
/* Read WASM/AOT file into a memory buffer */
wasmBytes := read_wasm_binary_to_buffer(...)
/* Load WASM/AOT module from the memory buffer */
module, err = wamr.NewModule(wasmBytes)
/* Create WASM/AOT instance from the module */
instance, err = wamr.NewInstance(module, 16384, 16384)
/* Call the `fib` function */
results = make([]interface{}, 1, 1)
err = instance.CallFuncV("fib", 1, results, (int32)32)
fmt.Printf("fib(32) return: %d\n", results[0].(int32));
/* Destroy runtime */
wamr.Runtime().Destroy()
```
More samples can be found in [test.go](./samples/test.go)

21
language-bindings/go/build.sh Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
PLATFORM=$(uname -s | tr A-Z a-z)
CUR_DIR=$PWD
WAMR_DIR=$PWD/../..
WAMR_GO_DIR=$PWD/wamr
cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include
mkdir -p build && cd build
cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \
-DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \
-DWAMR_BUILD_MEMORY_PROFILING=1
make -j ${nproc}
cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64
cd ${WAMR_GO_DIR}
go test

View File

@ -0,0 +1,5 @@
module gitlab.alipay-inc.com/TNT_Runtime/ant-runtime/bindings/go
go 1.15
require github.com/stretchr/testify v1.7.0

View File

@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
PLATFORM=$(uname -s | tr A-Z a-z)
CUR_DIR=$PWD
WAMR_DIR=$PWD/../../..
WAMR_GO_DIR=$PWD/../wamr
cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include
mkdir -p build && cd build
cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \
-DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \
-DWAMR_BUILD_MEMORY_PROFILING=1
make -j ${nproc}
cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64
cd ${CUR_DIR}
rm -f test
go build test.go
./test

View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
go build test.go
./test

View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package main
import (
"gitlab.alipay-inc.com/TNT_Runtime/ant-runtime/bindings/go/wamr"
"fmt"
)
var wasmBytes = []byte {
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x29, 0x07, 0x60,
0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01,
0x7F, 0x00, 0x60, 0x04, 0x7F, 0x7E, 0x7D, 0x7C, 0x00, 0x60, 0x02, 0x7E,
0x7E, 0x01, 0x7E, 0x60, 0x02, 0x7C, 0x7F, 0x01, 0x7D, 0x60, 0x02, 0x7D,
0x7C, 0x01, 0x7C, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70,
0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04,
0x70, 0x75, 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D,
0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x04,
0x66, 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x07, 0x06, 0x00, 0x03, 0x04,
0x06, 0x05, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x13, 0x03, 0x7F,
0x01, 0x41, 0x90, 0x29, 0x0B, 0x7F, 0x00, 0x41, 0x90, 0x09, 0x0B, 0x7F,
0x00, 0x41, 0x90, 0x29, 0x0B, 0x07, 0x5F, 0x09, 0x06, 0x6D, 0x65, 0x6D,
0x6F, 0x72, 0x79, 0x02, 0x00, 0x04, 0x66, 0x69, 0x62, 0x32, 0x00, 0x04,
0x05, 0x74, 0x65, 0x73, 0x74, 0x31, 0x00, 0x05, 0x05, 0x74, 0x65, 0x73,
0x74, 0x32, 0x00, 0x06, 0x05, 0x74, 0x65, 0x73, 0x74, 0x33, 0x00, 0x07,
0x05, 0x74, 0x65, 0x73, 0x74, 0x34, 0x00, 0x08, 0x10, 0x5F, 0x5F, 0x6D,
0x61, 0x69, 0x6E, 0x5F, 0x61, 0x72, 0x67, 0x63, 0x5F, 0x61, 0x72, 0x67,
0x76, 0x00, 0x09, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, 0x61, 0x5F, 0x65,
0x6E, 0x64, 0x03, 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, 0x61, 0x70, 0x5F,
0x62, 0x61, 0x73, 0x65, 0x03, 0x02, 0x0A, 0xA5, 0x03, 0x06, 0x37, 0x01,
0x01, 0x7F, 0x41, 0x01, 0x21, 0x01, 0x20, 0x00, 0x41, 0x02, 0x4F, 0x04,
0x7F, 0x41, 0x00, 0x21, 0x01, 0x03, 0x40, 0x20, 0x00, 0x41, 0x02, 0x6B,
0x10, 0x04, 0x20, 0x01, 0x6A, 0x21, 0x01, 0x20, 0x00, 0x41, 0x01, 0x6B,
0x22, 0x00, 0x41, 0x01, 0x4B, 0x0D, 0x00, 0x0B, 0x20, 0x01, 0x41, 0x01,
0x6A, 0x05, 0x41, 0x01, 0x0B, 0x0B, 0x3F, 0x01, 0x01, 0x7F, 0x23, 0x00,
0x41, 0x20, 0x6B, 0x22, 0x04, 0x24, 0x00, 0x20, 0x04, 0x41, 0x18, 0x6A,
0x20, 0x03, 0x39, 0x03, 0x00, 0x20, 0x04, 0x41, 0x10, 0x6A, 0x20, 0x02,
0xBB, 0x39, 0x03, 0x00, 0x20, 0x04, 0x20, 0x01, 0x37, 0x03, 0x08, 0x20,
0x04, 0x20, 0x00, 0x36, 0x02, 0x00, 0x41, 0xD0, 0x08, 0x20, 0x04, 0x10,
0x00, 0x1A, 0x20, 0x04, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x0B, 0x3B, 0x01,
0x01, 0x7F, 0x23, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, 0x24, 0x00, 0x20,
0x02, 0x20, 0x00, 0x37, 0x03, 0x00, 0x20, 0x02, 0x20, 0x01, 0x37, 0x03,
0x08, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20, 0x00, 0x20, 0x01, 0x7C, 0x22,
0x00, 0x37, 0x03, 0x00, 0x41, 0xF6, 0x08, 0x20, 0x02, 0x10, 0x00, 0x1A,
0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x20, 0x00, 0x0B, 0x40, 0x02,
0x01, 0x7F, 0x01, 0x7C, 0x23, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, 0x24,
0x00, 0x20, 0x02, 0x20, 0x01, 0x39, 0x03, 0x08, 0x20, 0x02, 0x20, 0x00,
0xBB, 0x22, 0x03, 0x39, 0x03, 0x00, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20,
0x03, 0x20, 0x01, 0xA2, 0x22, 0x01, 0x39, 0x03, 0x00, 0x41, 0xB4, 0x08,
0x20, 0x02, 0x10, 0x00, 0x1A, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x00,
0x20, 0x01, 0x0B, 0x3D, 0x01, 0x01, 0x7F, 0x23, 0x00, 0x41, 0x20, 0x6B,
0x22, 0x02, 0x24, 0x00, 0x20, 0x02, 0x20, 0x00, 0x39, 0x03, 0x00, 0x20,
0x02, 0x20, 0x01, 0x36, 0x02, 0x08, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20,
0x00, 0x20, 0x01, 0xB7, 0xA3, 0x22, 0x00, 0x39, 0x03, 0x00, 0x41, 0xC2,
0x08, 0x20, 0x02, 0x10, 0x00, 0x1A, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24,
0x00, 0x20, 0x00, 0xB6, 0x0B, 0x70, 0x00, 0x23, 0x00, 0x41, 0x20, 0x6B,
0x22, 0x00, 0x24, 0x00, 0x41, 0x9A, 0x08, 0x10, 0x01, 0x1A, 0x02, 0x7F,
0x41, 0x80, 0x08, 0x10, 0x02, 0x22, 0x01, 0x45, 0x04, 0x40, 0x41, 0x88,
0x08, 0x10, 0x01, 0x1A, 0x41, 0x7F, 0x0C, 0x01, 0x0B, 0x20, 0x00, 0x20,
0x01, 0x36, 0x02, 0x10, 0x41, 0xA7, 0x08, 0x20, 0x00, 0x41, 0x10, 0x6A,
0x10, 0x00, 0x1A, 0x20, 0x01, 0x41, 0x04, 0x6A, 0x41, 0x8E, 0x09, 0x2F,
0x00, 0x00, 0x3B, 0x00, 0x00, 0x20, 0x01, 0x41, 0x8A, 0x09, 0x28, 0x00,
0x00, 0x36, 0x00, 0x00, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x00, 0x41,
0x80, 0x08, 0x20, 0x00, 0x10, 0x00, 0x1A, 0x20, 0x01, 0x10, 0x03, 0x41,
0x00, 0x0B, 0x20, 0x00, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x0B, 0x0B, 0x97,
0x01, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x8F, 0x01, 0x62, 0x75, 0x66,
0x3A, 0x20, 0x25, 0x73, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x20,
0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00, 0x48,
0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00,
0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, 0x70, 0x0A,
0x00, 0x25, 0x66, 0x20, 0x2A, 0x20, 0x25, 0x66, 0x20, 0x3D, 0x20, 0x25,
0x66, 0x0A, 0x00, 0x25, 0x66, 0x20, 0x2F, 0x20, 0x25, 0x64, 0x20, 0x3D,
0x20, 0x25, 0x66, 0x0A, 0x00, 0x69, 0x33, 0x32, 0x3A, 0x20, 0x25, 0x64,
0x2C, 0x20, 0x69, 0x36, 0x34, 0x3A, 0x20, 0x25, 0x6C, 0x6C, 0x64, 0x2C,
0x20, 0x66, 0x33, 0x32, 0x3A, 0x20, 0x25, 0x66, 0x2C, 0x20, 0x66, 0x36,
0x34, 0x3A, 0x20, 0x25, 0x66, 0x0A, 0x00, 0x25, 0x6C, 0x6C, 0x64, 0x20,
0x2B, 0x20, 0x25, 0x6C, 0x6C, 0x64, 0x20, 0x3D, 0x20, 0x25, 0x6C, 0x6C,
0x64, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A }
var global_heap []byte = make([]byte, 128 * 1024, 128 * 1024)
func main() {
var module *wamr.Module
var instance *wamr.Instance
var argv []uint32
var results []interface{}
var offset uint32
var native_addr *uint8
var err error
fmt.Print("Init wasm runtime with global heap buf\n");
err = wamr.Runtime().FullInit(true, global_heap, 1)
if err != nil {
return
}
fmt.Print("Destroy runtime\n");
wamr.Runtime().Destroy()
fmt.Print("Init wasm runtime without global heap buf\n");
err = wamr.Runtime().FullInit(false, nil, 1)
if err != nil {
return
}
wamr.Runtime().SetLogLevel(wamr.LOG_LEVEL_WARNING)
fmt.Print("Load wasm module\n");
module, err = wamr.NewModule(wasmBytes)
if err != nil {
fmt.Println(err)
goto fail
}
fmt.Print("Instantiate wasm module\n");
instance, err = wamr.NewInstance(module, 16384, 16384)
if err != nil {
fmt.Println(err)
goto fail
}
results = make([]interface{}, 8, 8)
argv = make([]uint32, 8)
fmt.Print("\nCall func __main_argc_argv with CallFunc:\n");
err = instance.CallFunc("__main_argc_argv", 2, argv)
if err != nil {
fmt.Println(err)
goto fail
}
fmt.Print("\nCall func __main_argc_argv with CallFuncV:\n");
err = instance.CallFuncV("__main_argc_argv", 2, results,
(int32)(0), (int32)(0))
if err != nil {
fmt.Println(err)
goto fail
}
fmt.Print("\nCall func `i32 fib2(i32)` with CallFunc:\n");
argv[0] = 32
err = instance.CallFunc("fib2", 1, argv)
if err != nil {
fmt.Println(err)
goto fail
}
fmt.Printf("fib2(32) return: %d\n", argv[0]);
fmt.Print("\nCall func `void test1(i32, i64, f32, f64)` with CallFuncV:\n");
err = instance.CallFuncV("test1", 0, nil,
(int32)(12345678),
(int64)(3344556677889900),
(float32)(5678.1234),
(float64)(987654321.5678))
if err != nil {
fmt.Println(err)
goto fail
}
fmt.Print("\nCall func `i64 test2(i64, i64)` with CallFuncV:\n");
err = instance.CallFuncV("test2", 1, results,
(int64)(3344556677889900),
(int64)(1122331122110099))
if err != nil {
fmt.Println(err)
goto fail
}
fmt.Printf("test2(3344556677889900, 1122331122110099) return: %d\n",
results[0].(int64))
fmt.Print("\nCall func `f64 test3(f32, f64)` with CallFuncV:\n");
err = instance.CallFuncV("test3", 1, results,
(float32)(3456.1234),
(float64)(7890.4567))
if err != nil {
fmt.Println(err)
goto fail
}
fmt.Printf("test3(3456.1234, 7890.4567) return: %f\n",
results[0].(float64))
fmt.Print("\nCall func `f32 test4(f64, i32)` with CallFuncV:\n");
err = instance.CallFuncV("test4", 1, results,
(float64)(8912.3456),
(int32)(123))
if err != nil {
fmt.Println(err)
goto fail
}
fmt.Printf("test4(8912.3456, 123) return: %f\n",
results[0].(float32))
fmt.Print("\nTest ModuleMalloc")
offset, native_addr = instance.ModuleMalloc(1024)
fmt.Printf("ModuleMalloc(%d) return offset: %d, native addr: %p\n",
1024, offset, native_addr)
if (!instance.ValidateAppAddr(offset, 1024)) {
fmt.Print("Validate app addr failed\n")
}
if (!instance.ValidateNativeAddr(native_addr, 1024)) {
fmt.Print("Validate native addr failed\n")
}
if (native_addr != instance.AddrAppToNative(offset)) {
fmt.Print("Convert app addr to native addr failed\n")
}
if (offset != instance.AddrNativeToApp(native_addr)) {
fmt.Print("Convert app addr to native addr failed\n")
}
instance.ModuleFree(offset)
/*
instance.DumpMemoryConsumption()
instance.DumpCallStack()
*/
fmt.Print("\n");
fail:
if (instance != nil) {
fmt.Print("Destroy instance\n");
instance.Destroy()
}
if (module != nil) {
fmt.Print("Destroy module\n");
module.Destroy()
}
fmt.Print("Destroy wasm runtime\n");
wamr.Runtime().Destroy()
}

View File

@ -0,0 +1,32 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
WAMR_DIR=${PWD}/../../..
echo "Build wasm app .."
/opt/wasi-sdk/bin/clang -O3 \
-z stack-size=4096 -Wl,--initial-memory=65536 \
-o test.wasm main.c \
-Wl,--export=main -Wl,--export=__main_argc_argv \
-Wl,--export=fib2 \
-Wl,--export=test1 \
-Wl,--export=test2 \
-Wl,--export=test3 \
-Wl,--export=test4 \
-Wl,--export=__data_end -Wl,--export=__heap_base \
-Wl,--strip-all,--no-entry \
-Wl,--allow-undefined \
-nostdlib \
echo "Build binarydump tool .."
rm -fr build && mkdir build && cd build
cmake ../../../../../test-tools/binarydump-tool
make
cd ..
echo "Generate test_wasm.h .."
./build/binarydump -o test_wasm.h -n wasm_test_file test.wasm
rm -fr build
echo "Done"

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h>
#include <stdlib.h>
unsigned
fib2(unsigned n)
{
if (n < 2) {
return 1;
}
return fib2(n - 2) + fib2(n - 1);
}
void
test1(int32_t i32, int64_t i64, float f32, double f64)
{
printf("i32: %d, i64: %lld, f32: %f, f64: %f\n", i32, i64, f32, f64);
}
int64_t
test2(int64_t x, int64_t y)
{
printf("%lld + %lld = %lld\n", x, y, x + y);
return x + y;
}
double
test3(float x, double y)
{
printf("%f * %f = %f\n", x, y, x * y);
return x * y;
}
float
test4(double x, int32_t y)
{
printf("%f / %d = %f\n", x, y, x / y);
return x / y;
}
int
main(int argc, char **argv)
{
char *buf;
printf("Hello world!\n");
buf = malloc(1024);
if (!buf) {
printf("malloc buf failed\n");
return -1;
}
printf("buf ptr: %p\n", buf);
snprintf(buf, 1024, "%s", "1234\n");
printf("buf: %s", buf);
free(buf);
return 0;
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package wamr
// #cgo CFLAGS: -I${SRCDIR}/packaged/include
// #cgo LDFLAGS: -lvmlib -lm
//
// #cgo linux,amd64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/linux-amd64 -L${SRCDIR}/packaged/lib/linux-amd64
// #cgo linux,arm64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/linux-aarch64 -L${SRCDIR}/packaged/lib/linux-aarch64
// #cgo darwin,amd64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/darwin-amd64 -L${SRCDIR}/packaged/lib/darwin-amd64
// #cgo darwin,arm64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/darwin-aarch64 -L${SRCDIR}/packaged/lib/darwin-aarch64
//
// #include <wasm_export.h>
import "C"
import (
)

View File

@ -0,0 +1,385 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package wamr
/*
#include <stdlib.h>
#include <wasm_export.h>
static inline void
PUT_I64_TO_ADDR(uint32_t *addr, int64_t value)
{
union {
int64_t val;
uint32_t parts[2];
} u;
u.val = value;
addr[0] = u.parts[0];
addr[1] = u.parts[1];
}
static inline void
PUT_F64_TO_ADDR(uint32_t *addr, double value)
{
union {
double val;
uint32_t parts[2];
} u;
u.val = value;
addr[0] = u.parts[0];
addr[1] = u.parts[1];
}
static inline int64_t
GET_I64_FROM_ADDR(uint32_t *addr)
{
union {
int64_t val;
uint32_t parts[2];
} u;
u.parts[0] = addr[0];
u.parts[1] = addr[1];
return u.val;
}
static inline double
GET_F64_FROM_ADDR(uint32_t *addr)
{
union {
double val;
uint32_t parts[2];
} u;
u.parts[0] = addr[0];
u.parts[1] = addr[1];
return u.val;
}
*/
import "C"
import (
"runtime"
"unsafe"
"fmt"
)
type Instance struct {
_instance C.wasm_module_inst_t
_exec_env C.wasm_exec_env_t
_module *Module
_exportsCache map[string]C.wasm_function_inst_t
}
/* Create instance from the module */
func NewInstance(module *Module,
stackSize uint, heapSize uint) (*Instance, error) {
if (module == nil) {
return nil, fmt.Errorf("NewInstance error: invalid input")
}
errorBytes := make([]byte, 128)
errorPtr := (*C.char)(unsafe.Pointer(&errorBytes[0]))
errorLen := C.uint(len(errorBytes))
instance := C.wasm_runtime_instantiate(module.module, C.uint(stackSize),
C.uint(heapSize), errorPtr, errorLen)
if (instance == nil) {
return nil, fmt.Errorf("NewInstance Error: %s", string(errorBytes))
}
exec_env := C.wasm_runtime_create_exec_env(instance, C.uint(stackSize))
if (exec_env == nil) {
C.wasm_runtime_deinstantiate(instance)
return nil, fmt.Errorf("NewInstance Error: create exec_env failed")
}
self := &Instance{
_instance: instance,
_exec_env: exec_env,
_module: module,
_exportsCache: make(map[string]C.wasm_function_inst_t),
}
runtime.SetFinalizer(self, func(self *Instance) {
self.Destroy()
})
return self, nil
}
/* Destroy the instance */
func (self *Instance) Destroy() {
runtime.SetFinalizer(self, nil)
if (self._instance != nil) {
C.wasm_runtime_deinstantiate(self._instance)
}
if (self._exec_env != nil) {
C.wasm_runtime_destroy_exec_env(self._exec_env)
}
}
/* Call the wasm function with argument in the uint32 array, and store
the return values back into the array */
func (self *Instance) CallFunc(funcName string,
argc uint32, args []uint32) error {
_func := self._exportsCache[funcName]
if _func == nil {
cName := C.CString(funcName)
defer C.free(unsafe.Pointer(cName))
_func = C.wasm_runtime_lookup_function(self._instance,
cName, (*C.char)(C.NULL))
if _func == nil {
return fmt.Errorf("CallFunc error: lookup function failed")
}
self._exportsCache[funcName] = _func
}
thread_env_inited := Runtime().ThreadEnvInited()
if (!thread_env_inited) {
Runtime().InitThreadEnv()
}
var args_C *C.uint32_t
if (argc > 0) {
args_C = (*C.uint32_t)(unsafe.Pointer(&args[0]))
}
if (!C.wasm_runtime_call_wasm(self._exec_env, _func,
C.uint(argc), args_C)) {
if (!thread_env_inited) {
Runtime().DestroyThreadEnv()
}
return fmt.Errorf("CallFunc error: %s", string(self.GetException()))
}
if (!thread_env_inited) {
Runtime().DestroyThreadEnv()
}
return nil
}
/* Call the wasm function with variant arguments, and store the return
values back into the results array */
func (self *Instance) CallFuncV(funcName string,
num_results uint32, results []interface{},
args ... interface{}) error {
_func := self._exportsCache[funcName]
if _func == nil {
cName := C.CString(funcName)
defer C.free(unsafe.Pointer(cName))
_func = C.wasm_runtime_lookup_function(self._instance,
cName, (*C.char)(C.NULL))
if _func == nil {
return fmt.Errorf("CallFunc error: lookup function failed")
}
self._exportsCache[funcName] = _func
}
param_count := uint32(C.wasm_func_get_param_count(_func, self._instance))
result_count := uint32(C.wasm_func_get_result_count(_func, self._instance))
if (num_results < result_count) {
str := "CallFunc error: invalid result count %d, " +
"must be no smaller than %d"
return fmt.Errorf(str, num_results, result_count)
}
param_types := make([]C.uchar, param_count, param_count)
result_types := make([]C.uchar, result_count, result_count)
if (param_count > 0) {
C.wasm_func_get_param_types(_func, self._instance,
(*C.uchar)(unsafe.Pointer(&param_types[0])))
}
if (result_count > 0) {
C.wasm_func_get_result_types(_func, self._instance,
(*C.uchar)(unsafe.Pointer(&result_types[0])))
}
argv_size := param_count * 2
if (result_count > param_count) {
argv_size = result_count * 2
}
argv := make([]uint32, argv_size, argv_size)
var i, argc uint32
for _, arg := range args {
if (i >= param_count) {
break;
}
switch arg.(type) {
case int32:
if (param_types[i] != C.WASM_I32 &&
param_types[i] != C.WASM_FUNCREF &&
param_types[i] != C.WASM_ANYREF) {
str := "CallFunc error: invalid param type %d, " +
"expect i32 but got other"
return fmt.Errorf(str, param_types[i])
}
argv[argc] = (uint32)(arg.(int32))
argc++
break
case int64:
if (param_types[i] != C.WASM_I64) {
str := "CallFunc error: invalid param type %d, " +
"expect i64 but got other"
return fmt.Errorf(str, param_types[i])
}
addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
C.PUT_I64_TO_ADDR(addr, (C.int64_t)(arg.(int64)))
argc += 2
break
case float32:
if (param_types[i] != C.WASM_F32) {
str := "CallFunc error: invalid param type %d, " +
"expect f32 but got other"
return fmt.Errorf(str, param_types[i])
}
*(*C.float)(unsafe.Pointer(&argv[argc])) = (C.float)(arg.(float32))
argc++
break
case float64:
if (param_types[i] != C.WASM_F64) {
str := "CallFunc error: invalid param type %d, " +
"expect f64 but got other"
return fmt.Errorf(str, param_types[i])
}
addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
C.PUT_F64_TO_ADDR(addr, (C.double)(arg.(float64)))
argc += 2
break
default:
return fmt.Errorf("CallFunc error: unknown param type %d",
param_types[i])
}
i++
}
if (i < param_count) {
str := "CallFunc error: invalid param count, " +
"must be no smaller than %d"
return fmt.Errorf(str, param_count)
}
err := self.CallFunc(funcName, argc, argv)
if (err != nil) {
return err
}
argc = 0
for i = 0; i < result_count; i++ {
switch result_types[i] {
case C.WASM_I32:
case C.WASM_FUNCREF:
case C.WASM_ANYREF:
i32 := (int32)(argv[argc])
results[i] = i32
argc++
break
case C.WASM_I64:
addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
results[i] = (int64)(C.GET_I64_FROM_ADDR(addr))
argc += 2
break
case C.WASM_F32:
addr := (*C.float)(unsafe.Pointer(&argv[argc]))
results[i] = (float32)(*addr)
argc++
break
case C.WASM_F64:
addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
results[i] = (float64)(C.GET_F64_FROM_ADDR(addr))
argc += 2
break
}
}
return nil
}
/* Get exception info of the instance */
func (self *Instance) GetException() string {
cStr := C.wasm_runtime_get_exception(self._instance)
goStr := C.GoString(cStr)
return goStr
}
/* Allocate memory from the heap of the instance */
func (self Instance) ModuleMalloc(size uint32) (uint32, *uint8) {
var offset C.uint32_t
native_addrs := make([]*uint8, 1, 1)
ptr := unsafe.Pointer(&native_addrs[0])
offset = C.wasm_runtime_module_malloc(self._instance, (C.uint32_t)(size),
(*unsafe.Pointer)(ptr))
return (uint32)(offset), native_addrs[0]
}
/* Free memory to the heap of the instance */
func (self Instance) ModuleFree(offset uint32) {
C.wasm_runtime_module_free(self._instance, (C.uint32_t)(offset))
}
func (self Instance) ValidateAppAddr(app_offset uint32, size uint32) bool {
ret := C.wasm_runtime_validate_app_addr(self._instance,
(C.uint32_t)(app_offset),
(C.uint32_t)(size))
return (bool)(ret)
}
func (self Instance) ValidateStrAddr(app_str_offset uint32) bool {
ret := C.wasm_runtime_validate_app_str_addr(self._instance,
(C.uint32_t)(app_str_offset))
return (bool)(ret)
}
func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint32) bool {
native_ptr_C := (unsafe.Pointer)(native_ptr)
ret := C.wasm_runtime_validate_native_addr(self._instance,
native_ptr_C,
(C.uint32_t)(size))
return (bool)(ret)
}
func (self Instance) AddrAppToNative(app_offset uint32) *uint8 {
native_ptr := C.wasm_runtime_addr_app_to_native(self._instance,
(C.uint32_t)(app_offset))
return (*uint8)(native_ptr)
}
func (self Instance) AddrNativeToApp(native_ptr *uint8) uint32 {
native_ptr_C := (unsafe.Pointer)(native_ptr)
offset := C.wasm_runtime_addr_native_to_app(self._instance,
native_ptr_C)
return (uint32)(offset)
}
func (self Instance) GetAppAddrRange(app_offset uint32) (bool,
uint32,
uint32) {
var start_offset, end_offset C.uint32_t
ret := C.wasm_runtime_get_app_addr_range(self._instance,
(C.uint32_t)(app_offset),
&start_offset, &end_offset)
return (bool)(ret), (uint32)(start_offset), (uint32)(end_offset)
}
func (self Instance) GetNativeAddrRange(native_ptr *uint8) (bool,
*uint8,
*uint8) {
var start_addr, end_addr *C.uint8_t
native_ptr_C := (*C.uint8_t)((unsafe.Pointer)(native_ptr))
ret := C.wasm_runtime_get_native_addr_range(self._instance,
native_ptr_C,
&start_addr, &end_addr)
return (bool)(ret), (*uint8)(start_addr), (*uint8)(end_addr)
}
func (self Instance) DumpMemoryConsumption() {
C.wasm_runtime_dump_mem_consumption(self._exec_env)
}
func (self Instance) DumpCallStack() {
C.wasm_runtime_dump_call_stack(self._exec_env)
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package wamr
import (
//"github.com/stretchr/testify/assert"
"testing"
)
func TestInstance(t *testing.T) {
/* TODO */
}
func TestCallFunc(t *testing.T) {
/* TODO */
}

View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package wamr
// #include <wasm_export.h>
import "C"
import (
"unsafe"
"runtime"
"fmt"
)
type Module struct {
module C.wasm_module_t
}
/* Create WASM/AOT module from the memory buffer */
func NewModule(wasmBytes []byte) (*Module, error) {
if (wasmBytes == nil || len(wasmBytes) == 0) {
return nil, fmt.Errorf("NewModule error: invalid input")
}
wasmPtr := (*C.uint8_t)(unsafe.Pointer(&wasmBytes[0]))
wasmLen := C.uint(len(wasmBytes))
errorBytes := make([]byte, 128)
errorPtr := (*C.char)(unsafe.Pointer(&errorBytes[0]))
errorLen := C.uint(len(errorBytes))
m := C.wasm_runtime_load(wasmPtr, wasmLen, errorPtr, errorLen)
if (m == nil) {
return nil, fmt.Errorf("NewModule error: %s", string(errorBytes))
}
self := &Module{
module: m,
}
runtime.SetFinalizer(self, func(self *Module) {
self.Destroy()
})
return self, nil
}
/* Destroy the module */
func (self *Module) Destroy() {
runtime.SetFinalizer(self, nil)
if (self.module != nil) {
C.wasm_runtime_unload(self.module)
}
}
/* Set module's wasi arguments */
func (self *Module) SetWasiArgs(dirList [][]byte, mapDirList [][]byte,
env [][]byte, argv[][]byte) {
var dirPtr, mapDirPtr, envPtr, argvPtr **C.char
var dirCount, mapDirCount, envCount C.uint
var argc C.int
if (dirList != nil) {
dirPtr = (**C.char)(unsafe.Pointer(&dirList[0]))
dirCount = C.uint(len(dirList))
}
if (mapDirList != nil) {
mapDirPtr = (**C.char)(unsafe.Pointer(&mapDirList[0]))
mapDirCount = C.uint(len(mapDirList))
}
if (env != nil) {
envPtr = (**C.char)(unsafe.Pointer(&env[0]))
envCount = C.uint(len(env))
}
if (argv != nil) {
argvPtr = (**C.char)(unsafe.Pointer(&argv[0]))
argc = C.int(len(argv))
}
C.wasm_runtime_set_wasi_args(self.module, dirPtr, dirCount,
mapDirPtr, mapDirCount,
envPtr, envCount, argvPtr, argc)
}
/* Set module's wasi arguments */
func (self *Module) SetWasiArgsEx(dirList [][]byte, mapDirList [][]byte,
env [][]byte, argv[][]byte,
stdinfd int, stdoutfd int, stderrfd int) {
var dirPtr, mapDirPtr, envPtr, argvPtr **C.char
var dirCount, mapDirCount, envCount C.uint
var argc C.int
if (dirList != nil) {
dirPtr = (**C.char)(unsafe.Pointer(&dirList[0]))
dirCount = C.uint(len(dirList))
}
if (mapDirList != nil) {
mapDirPtr = (**C.char)(unsafe.Pointer(&mapDirList[0]))
mapDirCount = C.uint(len(mapDirList))
}
if (env != nil) {
envPtr = (**C.char)(unsafe.Pointer(&env[0]))
envCount = C.uint(len(env))
}
if (argv != nil) {
argvPtr = (**C.char)(unsafe.Pointer(&argv[0]))
argc = C.int(len(argv))
}
C.wasm_runtime_set_wasi_args_ex(self.module, dirPtr, dirCount,
mapDirPtr, mapDirCount,
envPtr, envCount, argvPtr, argc,
C.int(stdinfd), C.int(stdoutfd),
C.int(stderrfd))
}
/* Set module's wasi network address pool */
func (self *Module) SetWasiAddrPool(addrPool [][]byte) {
var addrPoolPtr **C.char
var addrPoolSize C.uint
if (addrPool != nil) {
addrPoolPtr = (**C.char)(unsafe.Pointer(&addrPool[0]))
addrPoolSize = C.uint(len(addrPool))
}
C.wasm_runtime_set_wasi_addr_pool(self.module, addrPoolPtr, addrPoolSize)
}

View File

@ -0,0 +1,15 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package wamr
import (
//"github.com/stretchr/testify/assert"
"testing"
)
func TestModule(t *testing.T) {
/* TODO */
}

View File

@ -0,0 +1,6 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package include

View File

@ -0,0 +1,6 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package darwin_amd64

View File

@ -0,0 +1,6 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package lib

View File

@ -0,0 +1,6 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package linux_amd64

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package wamr
/*
#include <stdlib.h>
#include <string.h>
#include <wasm_export.h>
void
bh_log_set_verbose_level(uint32_t level);
bool
init_wamr_runtime(bool alloc_with_pool, uint8_t *heap_buf,
uint32_t heap_size, uint32_t max_thread_num)
{
RuntimeInitArgs init_args;
memset(&init_args, 0, sizeof(RuntimeInitArgs));
if (alloc_with_pool) {
init_args.mem_alloc_type = Alloc_With_Pool;
init_args.mem_alloc_option.pool.heap_buf = heap_buf;
init_args.mem_alloc_option.pool.heap_size = heap_size;
}
else {
init_args.mem_alloc_type = Alloc_With_System_Allocator;
}
return wasm_runtime_full_init(&init_args);
}
*/
import "C"
import (
"fmt"
"unsafe"
)
type LogLevel uint32
const (
LOG_LEVEL_FATAL LogLevel = 0
LOG_LEVEL_ERROR LogLevel = 1
LOG_LEVEL_WARNING LogLevel = 2
LOG_LEVEL_DEBUG LogLevel = 3
LOG_LEVEL_VERBOSE LogLevel = 4
)
/*
type NativeSymbol struct {
symbol string
func_ptr *uint8
signature string
}
*/
type _Runtime struct {
initialized bool
}
var _runtime_singleton *_Runtime
/* Return the runtime singleton */
func Runtime() *_Runtime {
if (_runtime_singleton == nil) {
self := &_Runtime{}
_runtime_singleton = self
}
return _runtime_singleton;
}
/* Initialize the WASM runtime environment */
func (self *_Runtime) FullInit(alloc_with_pool bool, heap_buf []byte,
max_thread_num uint) error {
var heap_buf_C *C.uchar
if (self.initialized) {
return nil
}
if (alloc_with_pool) {
if (heap_buf == nil) {
return fmt.Errorf("Failed to init WAMR runtime")
}
heap_buf_C = (*C.uchar)(unsafe.Pointer(&heap_buf[0]))
}
if (!C.init_wamr_runtime((C.bool)(alloc_with_pool), heap_buf_C,
(C.uint)(len(heap_buf)),
(C.uint)(max_thread_num))) {
return fmt.Errorf("Failed to init WAMR runtime")
}
self.initialized = true
return nil
}
/* Initialize the WASM runtime environment */
func (self *_Runtime) Init() error {
return self.FullInit(false, nil, 1)
}
/* Destroy the WASM runtime environment */
func (self *_Runtime) Destroy() {
if (self.initialized) {
C.wasm_runtime_destroy()
self.initialized = false
}
}
/* Set log verbose level (0 to 5, default is 2),
larger level with more log */
func (self *_Runtime) SetLogLevel(level LogLevel) {
C.bh_log_set_verbose_level(C.uint32_t(level))
}
/*
func (self *_Runtime) RegisterNatives(moduleName string,
nativeSymbols []NativeSymbol) {
}
*/ /* TODO */
func (self *_Runtime) InitThreadEnv() bool {
if (!C.wasm_runtime_init_thread_env()) {
return false
}
return true
}
func (self *_Runtime) DestroyThreadEnv() {
C.wasm_runtime_destroy_thread_env();
}
func (self *_Runtime) ThreadEnvInited() bool {
if (!C.wasm_runtime_thread_env_inited()) {
return false
}
return true
}
/* Allocate memory from runtime memory environment */
func (self *_Runtime) Malloc(size uint32) *uint8 {
ptr := C.wasm_runtime_malloc((C.uint32_t)(size))
return (*uint8)(ptr)
}
/* Free memory to runtime memory environment */
func (self *_Runtime) Free(ptr *uint8) {
C.wasm_runtime_free((unsafe.Pointer)(ptr))
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
package wamr
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestRuntime(t *testing.T) {
res := false
if (Runtime() != nil) {
res = true;
}
assert.Equal(t, res, true)
err := Runtime().Init()
assert.NoError(t, err)
Runtime().Destroy()
err = Runtime().FullInit(false, nil, 6)
assert.NoError(t, err)
Runtime().Destroy()
err = Runtime().FullInit(false, nil, 0)
assert.NoError(t, err)
Runtime().Destroy()
heap_buf := make([]byte, 128 * 1024)
err = Runtime().FullInit(true, heap_buf, 4)
assert.NoError(t, err)
Runtime().Destroy()
Runtime().FullInit(false, nil, 0)
err = Runtime().FullInit(false, nil, 0)
assert.NoError(t, err)
Runtime().Destroy()
Runtime().Destroy()
}

160
language-bindings/python/.gitignore vendored Normal file
View File

@ -0,0 +1,160 @@
# Refer to https://github.com/github/gitignore/blob/main/Python.gitignore
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# virtual environment
Pipfile
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# VSCode settings
.vscode/

View File

@ -0,0 +1 @@
../../LICENSE

View File

@ -0,0 +1,31 @@
# wamr-python
## Installation
### Installing from the source code
Installing from local source tree is in _development mode_. The package appears to be installed but still is editable from the source tree.
```bash
$ python -m pip install -e /path/to/wamr-root/binding/python
```
## Usage
```python
import wamr.ffi as ffi
```
### Preparation
The binding will load the shared library _libiwasm.so_ from the WAMR repo. So before running the binding, you need to build the library yourself.
The default compile options are good enough.
Please be aware that `wasm_frame_xxx` and `wasm_trap_xxx` only work well when enabling `WAMR_BUILD_DUMP_CALL_STACK`.
### Examples
There is a [simple example](./samples/hello_procedural.py) to show how to use bindings. Actually, the python binding follows C-APIs. There it should be easy if be familiar with _programming with wasm-c-api_.
Unit test cases under _./tests_ could be another but more complete references.

View File

@ -0,0 +1,708 @@
# how to implement a python binding of WAMR
A python language binding of Wasm runtime allows its users to call a set of APIs of
the runtime from the python world. Those APIs maybe implemented in C, C++, or Rust.
In the WAMR case, a python binding allows APIs in `core/iwasm/include/wasm_c_api.h`
to be used in the python scripts. To achieve that, we will create two kinds
of stuff: wrappers of structured data types and wrappers of functions under the
help of _ctypes_.
Cyptes is a tool in the standard library for creating Python bindings. It
provides a low-level toolset for loading shared libraries and marshaling
data between Python and C. Other options include _cffi_, _pybind11_,
_cpython_ and so on. Because we tend to make the binding depending on least
items. The built-in module, _ctypes_, is a good choice.
## General rules to marshal
The core of the idea of a language binding is how to translate different
representations of types in different language.
### load libraries
The `ctypes` supports locating a dynamic link library in a way similar to the
compiler does.
Currently, `ctypes.LoadLibrary` supports:
- `CDLL`. Those libraries use the standard C calling conversion.
- `OleDLL` and `WinDLL`. Those libraries use the `stdcall` calling conversion on
Windows only
### fundamental datatypes
_ctypes_ provides [primitive C compatiable data types](https://docs.python.org/3/library/ctypes.html#fundamental-data-types).
Like `c_bool`, `c_byte`, `c_int`, `c_long` and so on.
> `c_int` represents the _C_ `signed int` datatype. On platforms where
> `sizeof(int) == sizeof(long)` it is an alias to `c_long`.
| c datatypes | ctypes |
| ------------------- | ----------------------- |
| bool | c_bool |
| byte_t | c_ubyte |
| char | c_char |
| float32_t | c_float |
| float64_t | c_double |
| int32_t | c_int32 |
| int64_t | c_int64 |
| intptr_t | c_void_p |
| size_t | c_size_t |
| uint8_t | c_uint8 |
| uint32_t | c_uint32 |
| void | None |
| wasm_byte_t | c_ubyte |
| wasm_externkind_t | c_uint8 |
| wasm_memory_pages_t | c_uint32 |
| wasm_mutability_t | c_bool |
| wasm_table_size_t | c_uint32 |
| wasm_valkind_t | c_uint8 |
| wasm_data_type\* | POINTER(wasm_data_type) |
- `c_void_p` only represents `void *` only
- `None` represents `void` in function parameter lists and return lists
### structured datatypes
Create a corresponding concept for every native structured data type includes
`enum`, `struct` and `union`, in the python world.
#### Enum types
For example, if there is a `enum wams_mutability_enum` in native.
```c
typedef uint8_t wams_mutability_t;
enum wams_mutability_enum {
WASM_CONST,
WASM_VAR
};
```
Use `ctypes.int`(or any integer types in ctypes) to represents its value directly.
```python
# represents enum wams_mutability_enum
wasm_mutability_t = c_uint8
WASM_CONST = 0
WASM_VAR = 1
```
> C standard only requires "Each enumerated type shall be compatible with char,
> a signed integer type, or an unsigned integer type. The choice of the integer
> type is implementation-defined, but shall be capable of representing the
> values of all the members of the enumeration.
#### Struct types
If there is a `struct wasm_byte_vec_t` in native(in C).
```c
typedef struct wasm_byte_vec_t {
size_t size;
wasm_byte_t *data;
size_t num_elems;
size_t size_of_elem;
} wasm_byte_vec_t;
```
Use `ctypes.Structure` to create its corresponding data type in python.
```python
class wasm_byte_vec_t(ctypes.Structure):
_fileds_ = [
("size", ctypes.c_size_t),
("data", ctypes.POINTER(c_ubyte)),
("num_elems", ctypes.c_size_t),
("size_of_elem", ctypes.c_size_t),
]
```
a list of `Structures`
| name |
| ----------------- |
| wasm_engine_t |
| wasm_store_t |
| wasm_limits_t |
| wasm_valtype_t |
| wasm_functype_t |
| wasm_globaltype_t |
| wasm_tabletype_t |
| wasm_memorytype_t |
| wasm_externtype_t |
| wasm_importtype_t |
| wasm_exporttype_t |
| wasm_ref_t |
| wasm_ref_t |
| wasm_frame_t |
| wasm_trap_t |
| wasm_foreign_t |
| WASMModuleCommon |
| WASMModuleCommon |
| wasm_func_t |
| wasm_global_t |
| wasm_table_t |
| wasm_memory_t |
| wasm_extern_t |
| wasm_instance_t |
not supported `struct`
- wasm_config_t
If there is an anonymous `union` in native.
```c
typedef struct wasm_val_t {
wasm_valkind_t kind;
union {
int32_t i32;
int64_t i64;
float32_t f32;
float64_t f64;
} of;
} wasm_val_t;
```
Use `ctypes.Union` to create its corresponding data type in python.
```python
class _OF(ctypes.Union):
_fields_ = [
("i32", ctypes.c_int32),
("i64", ctypes.c_int64),
("f32", ctypes.c_float),
("f64", ctypes.c_double),
]
class wasm_val_t(ctypes.Structure):
_anonymous_ = ("of",)
_fields_ = [
("kind", ctypes.c_uint8)
("of", _OF)
]
```
### wrappers of functions
Foreign functions (C functions) can be accessed as attributes of loaded shared
libraries or an instance of function prototypes. Callback functions(python
functions) can only be accessed by instantiating function prototypes.
For example,
```c
void wasm_name_new(wasm_name_t* out, size_t len, wasm_byte_t [] data);
```
Assume there are:
- `class wasm_name_t` of python represents `wasm_name_t` of C
- `libiwasm` represents loaded _libiwasm.so_
If to access a c function like an attribute,
```python
def wasm_name_new(out, len, data):
_wasm_name_new = libiwasm.wasm_name_new
_wasm_name_new.argtypes = (ctypes.POINTER(wasm_name_t), ctypes.c_size_t, ctypes.POINTER(ctypes.c_ubyte))
_wasm_name_new.restype = None
return _wasm_name_new(out, len, data)
```
Or to instantiate a function prototype,
```python
def wasm_name_new(out, len, data):
return ctypes.CFUNCTYPE(None, (ctypes.POINTER(wasm_name_t), ctypes.c_size_t, ctypes.POINTER(ctypes.c_ubyte)))(
("wasm_name_new", libiwasm), out, len, data)
```
Now it is able to create a `wasm_name_t` with `wasm_name_new()` in python.
Sometimes, need to create a python function as a callback of c.
```c
wasm_trap_t* (*wasm_func_callback_t)(wasm_val_vec_t* args, wasm_val_vec_t *results);
```
Use `cyptes.CFUNCTYPE` to create a _pointer of function_
```python
def hello(args, results):
print("hello from a callback")
wasm_func_callback_t = ctypes.CFUNCTYPE(c_size_t, POINTER(wasm_val_vec_t), POINTER(wasm_val_vec_t))
hello_callback = wasm_func_callback_t(hello)
```
or with a decorator
```python
def wasm_func_cb_decl(func):
return @ctypes.CFUNCTYPE(ctypes.POINTER(wasm_trap_t), (ctypes.POINTER(wasm_val_vec_t), ctypes.POINTER(wasm_val_vec_t)))(func)
@wasm_func_cb_decl
def hello(args, results):
print("hello from a callback")
```
### programming tips
#### `struct` and `ctypes.Structure`
There are two kinds of `cytes.Structure` in `binding.py`.
- has `__field__` definition. like `class wasm_byte_vec_t(Structure)`
- doesn't have `__field__` definition. like `class wasm_config_t(Structure)`
Since, `ctypes` will create its C world _mirror_ variable according to `__field__`
information, `wasm_config_t()` will only create a python instance without binding
to any C variable. `wasm_byte_vec_t()` will return a python instance with an internal
C variable.
That is why `pointer(wasm_config_t())` is a NULL pointer which can not be dereferenced.
#### deal with pointers
`byref()` and `pointer()` are two functions can return a pointer.
```python
x = ctypes.c_int(2)
# use pointer() to creates a new pointer instance which would later be used in Python
x_ptr = ctypes.pointer(x)
...
struct_use_pointer = Mystruct()
struct_use_pointer.ptr = x_ptr
# use byref() pass a pointer to an object to a foreign function call
func(ctypes.byref(x))
```
The main difference is that `pointer()` does a lot more work since it
constructs a real pointer object. It is faster to use `byref(`) if don't need
the pointer object in Python itself(e.g. only use it as an argument to pass
to a function).
There is no doubt that `wasm_xxx_new()` which return type is `ctypes.POINTER`
can return a pointer. Plus, the return value of `wasm_xxx_t()` can also be
used as a pointer without casting by `byref` or `pointer`.
#### array
In [ctypes document](https://docs.python.org/3/library/ctypes.html#arrays),
it states that "The recommended way to create array types is by multiplying a
data type with a positive integer". So _multiplying a data type_ should be a
better way to create arrays
```python
from ctypes import *
class POINT(Structure):
_fields_ = ("x", c_int), ("y", c_int)
# multiplying a data type
# type(TenPointsArrayType) is <class '_ctypes.PyCArrayType'>
TenPointsArrayType = POINT * 10
# Instances are created in the usual way, by calling the class:
arr = TenPointsArrayType()
arr[0] = POINT(3,2)
for pt in arr:
print(pt.x, pt.y)
```
On both sides, it is OK to assign an array to a pointer.
```c
char buf[128] = {0};
char *ptr = buf;
```
```python
binary = wasm_byte_vec_t()
binary.data = (ctypes.c_ubyte * len(wasm)).from_buffer_copy(wasm)
```
#### exceptions and traps
Interfaces of _wasm-c-api_ have their return values to represent failures.
The python binding should just keep and transfer them to callers instead of
raising any additional exception.
The python binding should raise exceptions when the python partial is failed.
#### readonly buffer
```python
with open("hello.wasm", "rb") as f:
wasm = f.read()
binary = wasm_byte_vec_t()
wasm_byte_vec_new_uninitialized(byref(binary), len(wasm))
# create a ctypes instance (byte[] in c) and copy the content
# from wasm(bytearray in python)
binary.data = (ctypes.c_ubyte * len(wasm)).from_buffer_copy(wasm)
```
in the above example, `wasm` is a python-created readable buffer. It is not
writable and needs to be copied into a ctype array.
#### variable arguments
A function with _variable arugments_ makes it hard to specify the required
argument types for the function prototype. It leaves us one way to call it
directly without any arguments type checking.
```python
libc.printf(b"Hello, an int %d, a float %f, a string %s\n", c_int(1), c_doulbe(3.14), "World!")
```
#### Use `c_bool` to represent `wasm_mutability_t `
- `True` for `WASM_CONST`
- `False` for `WASM_VALUE`
#### customize class builtins
- `__eq__` for comparation.
- `__repr__` for printing.
### bindgen.py
`bindge.py` is a tool to create WAMR python binding automatically. `binding.py`
is generated. We should avoid modification on it. Additional helpers should go
to `ffi.py`.
`bindgen.py` uses _pycparser_. Visit the AST of `core/iwasm/include/wasm_c_api.h`
created by _gcc_ and generate necessary wrappers.
```python
from pycparser import c_ast
class Visitor(c_ast.NodeVisitor):
def visit_Struct(self, node):
pass
def visit_Union(self, node):
pass
def visit_TypeDef(self, node):
pass
def visit_FuncDecl(self, node):
pass
ast = parse_file(...)
v = Visitor()
v.visit(ast)
```
Before running _bindgen.py_, the shared library _libiwasm.so_ should be generated.
```bash
$ cd /path/to/wamr/repo
$ # if it is in linux
$ pushd product-mini/platforms/linux/
$ cmake -S . -B build ..
$ cmake --build build --target iwasm
$ popd
$ cd binding/python
$ python utils/bindgen.py
```
`wasm_frame_xxx` and `wasm_trap_xxx` only work well when enabling `WAMR_BUILD_DUMP_CALL_STACK`.
```bash
$ cmake -S . -B build -DWAMR_BUILD_DUMP_CALL_STACK=1 ..
```
## OOP wrappers
Based on the above general rules, there will be corresponding python
APIs for every C API in `wasm_c_api.h` with same name. Users can do procedural
programming with those.
In next phase, we will create OOP APIs. Almost follow the
[C++ version of wasm_c_api](https://github.com/WebAssembly/wasm-c-api/blob/master/include/wasm.hh)
## A big list
| WASM Concept | Procedural APIs | OOP APIs | OOP APIs methods |
| ------------ | ------------------------------ | ---------- | ---------------- |
| XXX_vec | wasm_xxx_vec_new | | list |
| | wasm_xxx_vec_new_uninitialized | | |
| | wasm_xxx_vec_new_empty | | |
| | wasm_xxx_vec_copy | | |
| | wasm_xxx_vec_delete | | |
| valtype | wasm_valtype_new | valtype | \_\_init\_\_ |
| | wasm_valtype_delete | | \_\_del\_\_ |
| | wasm_valtype_kind | | \_\_eq\_\_ |
| | wasm_valtype_copy | | |
| | _vector methods_ | | |
| functype | wasm_functype_new | functype | |
| | wasm_functype_delete | | |
| | wasm_functype_params | | |
| | wasm_functype_results | | |
| | wasm_functype_copy | | |
| | _vector methods_ | | |
| globaltype | wasm_globaltype_new | globaltype | \_\_init\_\_ |
| | wasm_globaltype_delete | | \_\_del\_\_ |
| | wasm_globaltype_content | | \_\_eq\_\_ |
| | wasm_globaltype_mutability | | |
| | wasm_globaltype_copy | | |
| | _vector methods_ | | |
| tabletype | wasm_tabletype_new | tabletype | \_\_init\_\_ |
| | wasm_tabletype_delete | | \_\_del\_\_ |
| | wasm_tabletype_element | | \_\_eq\_\_ |
| | wasm_tabletype_limits | | |
| | wasm_tabletype_copy | | |
| | _vector methods_ | | |
| memorytype | wasm_memorytype_new | memorytype | \_\_init\_\_ |
| | wasm_memorytype_delete | | \_\_del\_\_ |
| | wasm_memorytype_limits | | \_\_eq\_\_ |
| | wasm_memorytype_copy | | |
| | _vector methods_ | | |
| externtype | wasm_externtype_as_XXX | externtype | |
| | wasm_XXX_as_externtype | | |
| | wasm_externtype_copy | | |
| | wasm_externtype_delete | | |
| | wasm_externtype_kind | | |
| | _vector methods_ | | |
| importtype | wasm_importtype_new | importtype | |
| | wasm_importtype_delete | | |
| | wasm_importtype_module | | |
| | wasm_importtype_name | | |
| | wasm_importtype_type | | |
| | wasm_importtype_copy | | |
| | _vector methods_ | | |
| exportype | wasm_exporttype_new | exporttype | |
| | wasm_exporttype_delete | | |
| | wasm_exporttype_name | | |
| | wasm_exporttype_type | | |
| | wasm_exporttype_copy | | |
| | _vector methods_ | | |
| val | wasm_val_delete | val | |
| | wasm_val_copy | | |
| | _vector methods_ | | |
| frame | wasm_frame_delete | frame | |
| | wasm_frame_instance | | |
| | wasm_frame_func_index | | |
| | wasm_frame_func_offset | | |
| | wasm_frame_module_offset | | |
| | wasm_frame_copy | | |
| | _vector methods_ | | |
| trap | wasm_trap_new | trap | |
| | wasm_trap_delete | | |
| | wasm_trap_message | | |
| | wasm_trap_origin | | |
| | wasm_trap_trace | | |
| | _vector methods_ | | |
| foreign | wasm_foreign_new | foreign | |
| | wasm_foreign_delete | | |
| | _vector methods_ | | |
| engine | wasm_engine_new | engine | |
| | wasm_engine_new_with_args\* | | |
| | wasm_engine_new_with_config | | |
| | wasm_engine_delete | | |
| store | wasm_store_new | store | |
| | wasm_store_delete | | |
| | _vector methods_ | | |
| module | wasm_module_new | module | |
| | wasm_module_delete | | |
| | wasm_module_validate | | |
| | wasm_module_imports | | |
| | wasm_module_exports | | |
| instance | wasm_instance_new | instance | |
| | wasm_instance_delete | | |
| | wasm_instance_new_with_args\* | | |
| | wasm_instance_exports | | |
| | _vector methods_ | | |
| func | wasm_func_new | func | |
| | wasm_func_new_with_env | | |
| | wasm_func_delete | | |
| | wasm_func_type | | |
| | wasm_func_call | | |
| | wasm_func_param_arity | | |
| | wasm_func_result_arity | | |
| | _vector methods_ | | |
| global | wasm_global_new | global | |
| | wasm_global_delete | | |
| | wasm_global_type | | |
| | wasm_global_get | | |
| | wasm_global_set | | |
| | _vector methods_ | | |
| table | wasm_table_new | table | |
| | wasm_table_delete | | |
| | wasm_table_type | | |
| | wasm_table_get | | |
| | wasm_table_set | | |
| | wasm_table_size | | |
| | _vector methods_ | | |
| memory | wasm_memory_new | memory | |
| | wasm_memory_delete | | |
| | wasm_memory_type | | |
| | wasm_memory_data | | |
| | wasm_memory_data_size | | |
| | wasm_memory_size | | |
| | _vector methods_ | | |
| extern | wasm_extern_delete | extern | |
| | wasm_extern_as_XXX | | |
| | wasm_XXX_as_extern | | |
| | wasm_extern_kind | | |
| | wasm_extern_type | | |
| | _vector methods_ | | |
not supported _functions_
- wasm_config_XXX
- wasm_module_deserialize
- wasm_module_serialize
- wasm_ref_XXX
- wasm_XXX_as_ref
- wasm_XXX_as_ref_const
- wasm_XXX_copy
- wasm_XXX_get_host_info
- wasm_XXX_set_host_info
## test
there will be two kinds of tests in the project
- unit test. located in `./tests`. driven by _unittest_. run by
`$ python -m unittest` or `$ make test`.
- integration test. located in `./samples`.
The whole project is under test-driven development. Every wrapper function will
have two kinds of test cases. The first kind is a positive case. It checks a
wrapper function with expected and safe arguments combinations. Its goal is the
function should work well with expected inputs. Another kind is a negative
case. It feeds unexpected arguments combinations into a wrapper function. Arguments
should include but not be limited to `None`. It ensures that the function will
gracefully handle invalid input or unexpected behaviors.
## distribution
### package
Create a python package named `wamr`. Users should import it after installation
just like any other python module.
```python
from wamr import *
```
### PyPI
Refer to [tutorial provided by PyPA](https://packaging.python.org/en/latest/tutorials/packaging-projects/).
Steps to publish WAMR Python library:
1. Creating `pyproject.toml` tells build tools (like pip and build) what is
required to build a project. An example .toml file uses _setuptools_
```toml
[build-system]
requires = [
"setuptools>=42",
"wheel"
]
build-backend = "setuptools.build_meta"
```
2. Configuring metadata tells build tools about a package (such as the name
and the version), as well as which code files to include
- Static metadata (`setup.cfg`): guaranteed to be the same every time.
It is simpler, easier to read, and avoids many common errors, like
encoding errors.
- Dynamic metadata (`setup.py`): possibly non-deterministic. Any items that
are dynamic or determined at install-time, as well as extension modules
or extensions to setuptools, need to go into setup.py.
**_Static metadata should be preferred_**. Dynamic metadata should be used
only as an escape hatch when necessary. setup.py used to be
required, but can be omitted with newer versions of setuptools and pip.
3. Including other files in the distribution
- For [source distribution](https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist):
It's usually generated using `python setup.py sdist`, providing metadata
and the essential source files needed for installing by a tool like pip,
or for generating a Built Distribution.
It includes our Python modules, pyproject.toml, metadata, README.md,
LICENSE. If you want to control what goes in this explicitly,
see [Including files in source distributions with MANIFEST.in](https://packaging.python.org/en/latest/guides/using-manifest-in/#using-manifest-in).
- For [final built distribution](https://packaging.python.org/en/latest/glossary/#term-Built-Distribution)
A Distribution format containing files and metadata that only need to be
moved to the correct location on the target system, to be installed.
e.g. `Wheel`
It will have the Python files in the discovered or listed Python packages.
If you want to control what goes here, such as to add data files,
see [Including Data Files](https://setuptools.pypa.io/en/latest/userguide/datafiles.html) from the [setuptools docs](https://setuptools.pypa.io/en/latest/index.html).
4. Generating distribution archives. These are archives that are uploaded to
the Python Package Index and can be installed by pip.
example using `setuptools`
```shell
python3 -m pip install --upgrade build
python3 -m build
```
generated files:
```shell
dist/
WAMR-package-0.0.1-py3-none-any.whl
WAMR-package-0.0.1.tar.gz
```
The `tar.gz` file is a _source archive_ whereas the `.whl file` is a
_built distribution_. Newer pip versions preferentially install built
distributions but will fall back to source archives if needed. You should
always upload a source archive and provide built archives for compatibility
reasons.
5. Uploading the distribution archives
- Register an account on https://pypi.org.
- To securely upload your project, youll need a
[PyPI API token](https://pypi.org/help/#apitoken). It can create at
[here](https://pypi.org/manage/account/#api-tokens), and the “Scope”
the setting needs to be “Entire account”.
- After registration, now twine can be used to upload the distribution packages.
```shell
# install twine
python3 -m pip install --upgrade twine
# --repository is https://pypi.org/ by default.
# You will be prompted for a username and password. For the username, use __token__. For the password, use the token value, including the pypi- prefix.
twine upload dist/*
```
after all, the python binding will be installed with
```shell
$ pip install wamr
```
PS: A example lifecycle of a python package
![python-package-lifecycle](images/python_package_life_cycle.png)
## CI
There are several parts:
- code format check.
- test. include running all unit test cases and examples.
- publish built distribution.

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

View File

@ -0,0 +1,12 @@
Use a python virtual environment tool to create an environment for development. All necessary packages are in _../requirements.txt_.
python code formatter is provided by _black_.
python code linter is provided by _pylint_ and default configuration.
Unit tests are driven by _unittest_.
```bash
$ python -m unittest -v tests/test_basics.py
$ python -m unittest -v tests/test_advanced.py
```

View File

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"

View File

@ -0,0 +1,5 @@
black
nose
pycparser
pylint

View File

@ -0,0 +1,4 @@
(module
(func $hello (import "" "hello"))
(func (export "run") (call $hello))
)

View File

@ -0,0 +1,41 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
import ctypes
from wamr import *
def hello_callback():
print("Calling back...")
print("> Hello World!")
def main():
print("Initializing...")
engine = Engine()
store = Store(engine)
print("Loading binary...")
print("Compiling module...")
module = Module.from_file(engine, "./hello.wasm")
print("Creating callback...")
hello = Func(store, FuncType([], []), hello_callback)
print("Instantiating module...")
instance = Instance(store, module, [hello])
print("Extracting export...")
run = instance.exports(store)["run"]
print("Calling export...")
run(store)
print("Shutting down...")
print("Done.")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
import ctypes
import wamr.ffi as ffi
WAMS_BINARY_CONTENT = (
b"\x00asm\x01\x00\x00\x00\x01\x84\x80\x80\x80\x00\x01`\x00\x00\x02\x8a\x80"
b"\x80\x80\x00\x01\x00\x05hello\x00\x00\x03\x82\x80\x80\x80\x00\x01\x00"
b"\x07\x87\x80\x80\x80\x00\x01\x03run\x00\x01\n\x8a\x80\x80\x80\x00\x01"
b"\x84\x80\x80\x80\x00\x00\x10\x00\x0b"
)
@ffi.wasm_func_cb_decl
def hello_callback(args, results):
print("Calling back...")
print("> Hello World!")
def main():
print("Initializing...")
engine = ffi.wasm_engine_new()
store = ffi.wasm_store_new(engine)
print("Loading binary...")
# for convenience, use binary content instead of open file
# with open("./hello.wasm", "rb") as f:
# wasm = f.read()
wasm = WAMS_BINARY_CONTENT
binary = ffi.wasm_byte_vec_t()
ffi.wasm_byte_vec_new_uninitialized(binary, len(wasm))
# underlying buffer is not writable
binary.data = (ctypes.c_ubyte * len(wasm)).from_buffer_copy(wasm)
print("Compiling module...")
module = ffi.wasm_module_new(store, binary)
if not module:
raise RuntimeError("Compiling module failed")
binary.data = None
ffi.wasm_byte_vec_delete(binary)
print("Creating callback...")
hello_type = ffi.wasm_functype_new_0_0()
hello_func = ffi.wasm_func_new(
store,
hello_type,
hello_callback,
)
ffi.wasm_functype_delete(hello_type)
print("Instantiating module...")
imports = ffi.wasm_extern_vec_t()
ffi.wasm_extern_vec_new((imports), 1, ffi.wasm_func_as_extern(hello_func))
instance = ffi.wasm_instance_new(store, module, imports, None)
ffi.wasm_func_delete(hello_func)
print("Extracting export...")
exports = ffi.wasm_extern_vec_t()
ffi.wasm_instance_exports(instance, exports)
run_func = ffi.wasm_extern_as_func(exports.data[0])
if not run_func:
raise RuntimeError("can not extract exported function")
ffi.wasm_instance_delete(instance)
ffi.wasm_module_delete(module)
print("Calling export...")
args = ffi.wasm_val_vec_t()
results = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(args)
ffi.wasm_val_vec_new_empty(results)
ffi.wasm_func_call(run_func, args, results)
print("Shutting down...")
ffi.wasm_store_delete(store)
ffi.wasm_engine_delete(engine)
print("Done.")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# pylint: disable=missing-class-docstring
# pylint: disable=missing-function-docstring
# pylint: disable=missing-module-docstring
from setuptools import setup, find_packages
with open("README.md") as f:
readme = f.read()
with open("LICENSE") as f:
license = f.read()
setup(
name="wamr-python",
version="0.1.0",
description="A WebAssembly runtime powered by WAMR",
long_description=readme,
author="The WAMR Project Developers",
author_email="hello@bytecodealliance.org",
url="https://github.com/bytecodealliance/wamr-python",
license=license,
packages=["wamr"],
)

View File

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
__all__ = ["test_basic", "test_advanced"]

View File

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import wamr

View File

@ -0,0 +1,525 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# pylint: disable=missing-class-docstring
# pylint: disable=missing-function-docstring
# pylint: disable=missing-module-docstring
import ctypes as c
import math
import unittest
import wamr.ffi as ffi
# It is a module likes:
# (module
# (import "mod" "g0" (global i32))
# (import "mod" "f0" (func (param f32) (result f64)))
#
# (func (export "f1") (param i32 i64))
# (global (export "g1") (mut f32) (f32.const 3.14))
# (memory (export "m1") 1 2)
# (table (export "t1") 1 funcref)
#
# (func (export "f2") (unreachable))
# )
MODULE_BINARY = (
b"\x00asm\x01\x00\x00\x00\x01\x0e\x03`\x01}\x01|`\x02\x7f~\x00`\x00"
b"\x00\x02\x14\x02\x03mod\x02g0\x03\x7f\x00\x03mod\x02f0\x00\x00\x03\x03"
b"\x02\x01\x02\x04\x04\x01p\x00\x01\x05\x04\x01\x01\x01\x02\x06\t\x01}\x01C"
b"\xc3\xf5H@\x0b\x07\x1a\x05\x02f1\x00\x01\x02g1\x03\x01\x02m1\x02\x00\x02t1"
b"\x01\x00\x02f2\x00\x02\n\x08\x02\x02\x00\x0b\x03\x00\x00\x0b"
)
# False -> True when testing with a library enabling WAMR_BUILD_DUMP_CALL_STACK flag
TEST_WITH_WAMR_BUILD_DUMP_CALL_STACK = False
@ffi.wasm_func_cb_decl
def callback(args, results):
args = ffi.dereference(args)
results = ffi.dereference(results)
arg_v = args.data[0]
result_v = ffi.wasm_f64_val(arg_v.of.f32 * 2.0)
ffi.wasm_val_copy(results.data[0], result_v)
results.num_elems = 1
print(f"\nIn callback: {arg_v} --> {result_v}\n")
@ffi.wasm_func_with_env_cb_decl
def callback_with_env(env, args, results):
# pylint: disable=unused-argument
print("summer")
class AdvancedTestSuite(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("Initializing...")
cls._wasm_engine = ffi.wasm_engine_new()
cls._wasm_store = ffi.wasm_store_new(cls._wasm_engine)
def assertIsNullPointer(self, pointer):
# pylint: disable=invalid-name
if not ffi.is_null_pointer(pointer):
self.fail("not a non-null pointer")
def assertIsNotNullPointer(self, pointer):
# pylint: disable=invalid-name
if ffi.is_null_pointer(pointer):
self.fail("not a non-null pointer")
def load_binary(self, binary_string):
print("Load binary...")
binary = ffi.load_module_file(binary_string)
binary = c.pointer(binary)
self.assertIsNotNullPointer(binary)
return binary
def compile(self, binary):
print("Compile...")
module = ffi.wasm_module_new(self._wasm_store, binary)
self.assertIsNotNullPointer(module)
return module
def prepare_imports_local(self):
print("Prepare imports...")
func_type = ffi.wasm_functype_new_1_1(
ffi.wasm_valtype_new(ffi.WASM_F32),
ffi.wasm_valtype_new(ffi.WASM_F64),
)
func = ffi.wasm_func_new(self._wasm_store, func_type, callback)
self.assertIsNotNullPointer(func)
ffi.wasm_functype_delete(func_type)
glbl_type = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
init = ffi.wasm_i32_val(1024)
glbl = ffi.wasm_global_new(self._wasm_store, glbl_type, init)
self.assertIsNotNullPointer(glbl)
ffi.wasm_globaltype_delete(glbl_type)
imports = ffi.wasm_extern_vec_t()
data = ffi.list_to_carray(
c.POINTER(ffi.wasm_extern_t),
ffi.wasm_func_as_extern(func),
ffi.wasm_global_as_extern(glbl),
)
ffi.wasm_extern_vec_new(imports, 2, data)
imports = c.pointer(imports)
self.assertIsNotNullPointer(imports)
return imports
def instantiate(self, module, imports):
print("Instantiate module...")
instance = ffi.wasm_instance_new(
self._wasm_store, module, imports, ffi.create_null_pointer(ffi.wasm_trap_t)
)
self.assertIsNotNone(instance)
self.assertIsNotNullPointer(instance)
return instance
def extract_exports(self, instance):
print("Extracting exports...")
exports = ffi.wasm_extern_vec_t()
ffi.wasm_instance_exports(instance, exports)
exports = c.pointer(exports)
self.assertIsNotNullPointer(exports)
return exports
def setUp(self):
binary = self.load_binary(MODULE_BINARY)
self.module = self.compile(binary)
self.imports = self.prepare_imports_local()
self.instance = self.instantiate(self.module, self.imports)
self.exports = self.extract_exports(self.instance)
ffi.wasm_byte_vec_delete(binary)
def tearDown(self):
if self.imports:
ffi.wasm_extern_vec_delete(self.imports)
if self.exports:
ffi.wasm_extern_vec_delete(self.exports)
ffi.wasm_instance_delete(self.instance)
ffi.wasm_module_delete(self.module)
def test_wasm_func_call_wasm(self):
export_list = ffi.wasm_vec_to_list(self.exports)
print(export_list)
func = ffi.wasm_extern_as_func(export_list[0])
self.assertIsNotNullPointer(func)
# make a call
params = ffi.wasm_val_vec_t()
data = ffi.list_to_carray(
ffi.wasm_val_t,
ffi.wasm_i32_val(1024),
ffi.wasm_i64_val(1024 * 1024),
)
ffi.wasm_val_vec_new(params, 2, data)
results = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(results)
ffi.wasm_func_call(func, params, results)
def test_wasm_func_call_native(self):
import_list = ffi.wasm_vec_to_list(self.imports)
func = ffi.wasm_extern_as_func(import_list[0])
self.assertIsNotNullPointer(func)
params = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new(
params, 1, ffi.list_to_carray(ffi.wasm_val_t, ffi.wasm_f32_val(3.14))
)
results = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_uninitialized(results, 1)
ffi.wasm_func_call(func, params, results)
self.assertEqual(params.data[0].of.f32 * 2, results.data[0].of.f64)
def test_wasm_func_call_wrong_params(self):
export_list = ffi.wasm_vec_to_list(self.exports)
func = ffi.wasm_extern_as_func(export_list[0])
# make a call
params = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(params)
results = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(results)
trap = ffi.wasm_func_call(func, params, results)
self.assertIsNotNullPointer(trap)
def test_wasm_func_call_unlinked(self):
ft = ffi.wasm_functype_new_0_0()
func = ffi.wasm_func_new(self._wasm_store, ft, callback)
params = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(params)
results = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(results)
trap = ffi.wasm_func_call(func, params, results)
ffi.wasm_func_delete(func)
def test_wasm_global_get_wasm(self):
export_list = ffi.wasm_vec_to_list(self.exports)
glb = ffi.wasm_extern_as_global(export_list[1])
self.assertIsNotNullPointer(glb)
# access the global
val = ffi.wasm_val_t()
ffi.wasm_global_get(glb, val)
self.assertAlmostEqual(val.of.f32, 3.14, places=3)
def test_wasm_global_get_native(self):
import_list = ffi.wasm_vec_to_list(self.imports)
glb = ffi.wasm_extern_as_global(import_list[1])
self.assertIsNotNullPointer(glb)
val = ffi.wasm_val_t()
ffi.wasm_global_get(glb, val)
self.assertEqual(val.of.i32, 1024)
def test_wasm_global_get_unlinked(self):
gt = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
init = ffi.wasm_i32_val(32)
glbl = ffi.wasm_global_new(self._wasm_store, gt, init)
val_ret = ffi.wasm_f32_val(3.14)
ffi.wasm_global_get(glbl, val_ret)
ffi.wasm_global_delete(glbl)
# val_ret wasn't touched, keep the original value
self.assertAlmostEqual(val_ret.of.f32, 3.14, 3)
def test_wasm_global_get_null_val(self):
export_list = ffi.wasm_vec_to_list(self.exports)
glb = ffi.wasm_extern_as_global(export_list[1])
ffi.wasm_global_get(glb, ffi.create_null_pointer(ffi.wasm_val_t))
def test_wasm_global_get_null_global(self):
val = ffi.wasm_val_t()
ffi.wasm_global_get(ffi.create_null_pointer(ffi.wasm_global_t), val)
def test_wasm_global_set_wasm(self):
export_list = ffi.wasm_vec_to_list(self.exports)
glb = ffi.wasm_extern_as_global(export_list[1])
self.assertIsNotNullPointer(glb)
# access the global
new_val = ffi.wasm_f32_val(math.e)
ffi.wasm_global_set(glb, new_val)
val = ffi.wasm_val_t()
ffi.wasm_global_get(glb, val)
self.assertNotEqual(val.of.f32, 3.14)
def test_wasm_global_set_native(self):
import_list = ffi.wasm_vec_to_list(self.imports)
glb = ffi.wasm_extern_as_global(import_list[1])
self.assertIsNotNullPointer(glb)
new_val = ffi.wasm_i32_val(2048)
ffi.wasm_global_set(glb, new_val)
val = ffi.wasm_val_t()
ffi.wasm_global_get(glb, val)
self.assertEqual(val, new_val)
def test_wasm_global_set_unlinked(self):
gt = ffi.wasm_globaltype_new(ffi.wasm_valtype_new(ffi.WASM_I32), True)
init = ffi.wasm_i32_val(32)
glbl = ffi.wasm_global_new(self._wasm_store, gt, init)
val_ret = ffi.wasm_f32_val(3.14)
ffi.wasm_global_set(glbl, val_ret)
ffi.wasm_global_delete(glbl)
def test_wasm_global_set_null_v(self):
export_list = ffi.wasm_vec_to_list(self.exports)
glb = ffi.wasm_extern_as_global(export_list[1])
# access the global
ffi.wasm_global_set(glb, ffi.create_null_pointer(ffi.wasm_val_t))
def test_wasm_global_set_null_global(self):
# access the global
new_val = ffi.wasm_f32_val(math.e)
ffi.wasm_global_set(ffi.create_null_pointer(ffi.wasm_global_t), new_val)
def test_wasm_table_size(self):
export_list = ffi.wasm_vec_to_list(self.exports)
tbl = ffi.wasm_extern_as_table(export_list[3])
self.assertIsNotNullPointer(tbl)
tbl_sz = ffi.wasm_table_size(tbl)
self.assertEqual(tbl_sz, 1)
def test_wasm_table_size_unlink(self):
vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
limits = ffi.wasm_limits_new(10, 15)
tt = ffi.wasm_tabletype_new(vt, limits)
tbl = ffi.wasm_table_new(
self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
)
tbl_sz = ffi.wasm_table_size(tbl)
ffi.wasm_table_delete(tbl)
def test_wasm_table_size_null_table(self):
ffi.wasm_table_size(ffi.create_null_pointer(ffi.wasm_table_t))
def test_wasm_table_get(self):
export_list = ffi.wasm_vec_to_list(self.exports)
tbl = ffi.wasm_extern_as_table(export_list[3])
self.assertIsNotNullPointer(tbl)
ref = ffi.wasm_table_get(tbl, 0)
self.assertIsNullPointer(ref)
ref = ffi.wasm_table_get(tbl, 4096)
self.assertIsNullPointer(ref)
def test_wasm_table_get_unlinked(self):
vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
limits = ffi.wasm_limits_new(10, 15)
tt = ffi.wasm_tabletype_new(vt, limits)
tbl = ffi.wasm_table_new(
self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
)
ffi.wasm_table_get(tbl, 0)
ffi.wasm_table_delete(tbl)
def test_wasm_table_get_null_table(self):
ffi.wasm_table_get(ffi.create_null_pointer(ffi.wasm_table_t), 0)
def test_wasm_table_get_out_of_bounds(self):
export_list = ffi.wasm_vec_to_list(self.exports)
tbl = ffi.wasm_extern_as_table(export_list[3])
ffi.wasm_table_get(tbl, 1_000_000_000)
def test_wasm_ref(self):
export_list = ffi.wasm_vec_to_list(self.exports)
func = ffi.wasm_extern_as_func(export_list[0])
self.assertIsNotNullPointer(func)
ref = ffi.wasm_func_as_ref(func)
self.assertIsNotNullPointer(ref)
func_from_ref = ffi.wasm_ref_as_func(ref)
self.assertEqual(
ffi.dereference(ffi.wasm_func_type(func)),
ffi.dereference(ffi.wasm_func_type(func_from_ref)),
)
def test_wasm_table_set(self):
export_list = ffi.wasm_vec_to_list(self.exports)
tbl = ffi.wasm_extern_as_table(export_list[3])
self.assertIsNotNullPointer(tbl)
func = ffi.wasm_extern_as_func(export_list[0])
ref = ffi.wasm_func_as_ref(func)
ffi.wasm_table_set(tbl, 0, ref)
ref_ret = ffi.wasm_table_get(tbl, 0)
self.assertIsNotNullPointer(ref_ret)
func_ret = ffi.wasm_ref_as_func(ref_ret)
self.assertEqual(
ffi.dereference(ffi.wasm_func_type(func)),
ffi.dereference(ffi.wasm_func_type(func_ret)),
)
def test_wasm_table_set_unlinked(self):
vt = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
limits = ffi.wasm_limits_new(10, 15)
tt = ffi.wasm_tabletype_new(vt, limits)
tbl = ffi.wasm_table_new(
self._wasm_store, tt, ffi.create_null_pointer(ffi.wasm_ref_t)
)
export_list = ffi.wasm_vec_to_list(self.exports)
func = ffi.wasm_extern_as_func(export_list[0])
ref = ffi.wasm_func_as_ref(func)
ffi.wasm_table_set(tbl, 0, ref)
ffi.wasm_table_delete(tbl)
def test_wasm_table_set_null_table(self):
export_list = ffi.wasm_vec_to_list(self.exports)
func = ffi.wasm_extern_as_func(export_list[0])
ref = ffi.wasm_func_as_ref(func)
ffi.wasm_table_set(ffi.create_null_pointer(ffi.wasm_table_t), 0, ref)
def test_wasm_table_set_null_ref(self):
export_list = ffi.wasm_vec_to_list(self.exports)
tbl = ffi.wasm_extern_as_table(export_list[3])
ffi.wasm_table_set(tbl, 0, ffi.create_null_pointer(ffi.wasm_ref_t))
def test_wasm_table_set_out_of_bounds(self):
export_list = ffi.wasm_vec_to_list(self.exports)
tbl = ffi.wasm_extern_as_table(export_list[3])
func = ffi.wasm_extern_as_func(export_list[0])
ref = ffi.wasm_func_as_ref(func)
ffi.wasm_table_set(tbl, 1_000_000_000, ref)
def test_wasm_memory_size(self):
export_list = ffi.wasm_vec_to_list(self.exports)
mem = ffi.wasm_extern_as_memory(export_list[2])
self.assertIsNotNullPointer(mem)
pg_sz = ffi.wasm_memory_size(mem)
self.assertEqual(pg_sz, 1)
def test_wasm_memory_size_unlinked(self):
limits = ffi.wasm_limits_new(10, 12)
mt = ffi.wasm_memorytype_new(limits)
mem = ffi.wasm_memory_new(self._wasm_store, mt)
ffi.wasm_memory_size(mem)
ffi.wasm_memory_delete(mem)
def test_wasm_memory_data(self):
export_list = ffi.wasm_vec_to_list(self.exports)
mem = ffi.wasm_extern_as_memory(export_list[2])
self.assertIsNotNullPointer(mem)
data_base = ffi.wasm_memory_data(mem)
self.assertIsNotNone(data_base)
def test_wasm_memory_data_unlinked(self):
limits = ffi.wasm_limits_new(10, 12)
mt = ffi.wasm_memorytype_new(limits)
mem = ffi.wasm_memory_new(self._wasm_store, mt)
ffi.wasm_memory_data(mem)
ffi.wasm_memory_delete(mem)
def test_wasm_memory_data_size(self):
export_list = ffi.wasm_vec_to_list(self.exports)
mem = ffi.wasm_extern_as_memory(export_list[2])
self.assertIsNotNullPointer(mem)
mem_sz = ffi.wasm_memory_data_size(mem)
self.assertGreater(mem_sz, 0)
def test_wasm_memory_data_size_unlinked(self):
limits = ffi.wasm_limits_new(10, 12)
mt = ffi.wasm_memorytype_new(limits)
mem = ffi.wasm_memory_new(self._wasm_store, mt)
ffi.wasm_memory_data_size(mem)
ffi.wasm_memory_delete(mem)
def test_wasm_trap(self):
export_list = ffi.wasm_vec_to_list(self.exports)
func = ffi.wasm_extern_as_func(export_list[0])
# make a call
params = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(params)
results = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(results)
trap = ffi.wasm_func_call(func, params, results)
self.assertIsNotNullPointer(trap)
message = ffi.wasm_message_t()
ffi.wasm_trap_message(trap, message)
self.assertIsNotNullPointer(c.pointer(message))
# not a function internal exception
frame = ffi.wasm_trap_origin(trap)
self.assertIsNullPointer(frame)
@unittest.skipUnless(
TEST_WITH_WAMR_BUILD_DUMP_CALL_STACK,
"need to enable WAMR_BUILD_DUMP_CALL_STACK",
)
# assertions only works if enabling WAMR_BUILD_DUMP_CALL_STACK
def test_wasm_frame(self):
export_list = ffi.wasm_vec_to_list(self.exports)
func = ffi.wasm_extern_as_func(export_list[4])
# make a call
params = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(params)
results = ffi.wasm_val_vec_t()
ffi.wasm_val_vec_new_empty(results)
print("Making a call...")
trap = ffi.wasm_func_call(func, params, results)
message = ffi.wasm_message_t()
ffi.wasm_trap_message(trap, message)
self.assertIsNotNullPointer(c.pointer(message))
print(message)
frame = ffi.wasm_trap_origin(trap)
self.assertIsNotNullPointer(frame)
print(ffi.dereference(frame))
traces = ffi.wasm_frame_vec_t()
ffi.wasm_trap_trace(trap, traces)
self.assertIsNotNullPointer(c.pointer(frame))
instance = ffi.wasm_frame_instance(frame)
self.assertIsNotNullPointer(instance)
module_offset = ffi.wasm_frame_module_offset(frame)
func_index = ffi.wasm_frame_func_index(frame)
self.assertEqual(func_index, 2)
func_offset = ffi.wasm_frame_func_offset(frame)
self.assertGreater(func_offset, 0)
@classmethod
def tearDownClass(cls):
print("Shutting down...")
ffi.wasm_store_delete(cls._wasm_store)
ffi.wasm_engine_delete(cls._wasm_engine)
if __name__ == "__main__":
unittest.main()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,386 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# pylint: disable=missing-class-docstring
# pylint: disable=missing-function-docstring
# pylint: disable=missing-module-docstring
"""
- Need to run *download_wamr.py* firstly.
- Parse *./wasm-micro-runtime/core/iwasm/include/wasm_c_api.h* and generate
*wamr/binding.py*
"""
import os
import pathlib
import shutil
import sys
from pycparser import c_ast, parse_file
WASM_C_API_HEADER = "core/iwasm/include/wasm_c_api.h"
BINDING_PATH = "wamr/binding.py"
# 4 spaces as default indent
INDENT = " "
IGNORE_SYMOLS = (
"wasm_engine_new_with_args",
"wasm_valkind_is_num",
"wasm_valkind_is_ref",
"wasm_valtype_is_num",
"wasm_valtype_is_ref",
"wasm_valtype_new_i32",
"wasm_valtype_new_i64",
"wasm_valtype_new_f32",
"wasm_valtype_new_f64",
"wasm_valtype_new_anyref",
"wasm_valtype_new_funcref",
"wasm_functype_new_0_0",
"wasm_functype_new_0_0",
"wasm_functype_new_1_0",
"wasm_functype_new_2_0",
"wasm_functype_new_3_0",
"wasm_functype_new_0_1",
"wasm_functype_new_1_1",
"wasm_functype_new_2_1",
"wasm_functype_new_3_1",
"wasm_functype_new_0_2",
"wasm_functype_new_1_2",
"wasm_functype_new_2_2",
"wasm_functype_new_3_2",
"wasm_val_init_ptr",
"wasm_val_ptr",
"wasm_val_t",
"wasm_ref_t",
"wasm_name_new_from_string",
"wasm_name_new_from_string_nt",
)
class Visitor(c_ast.NodeVisitor):
def __init__(self):
self.type_map = {
"_Bool": "c_bool",
"byte_t": "c_ubyte",
"char": "c_char",
"errno_t": "c_int",
"int": "c_int",
"long": "c_long",
"size_t": "c_size_t",
"uint32_t": "c_uint32",
"uint8_t": "c_uint8",
"void": "None",
}
self.ret = (
"# -*- coding: utf-8 -*-\n"
"#!/usr/bin/env python3\n"
"#\n"
"# Copyright (C) 2019 Intel Corporation. All rights reserved.\n"
"# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
"#\n"
"#It is a generated file. DO NOT EDIT.\n"
"#\n"
"from ctypes import *\n"
"\n"
"from .ffi import dereference, libiwasm, wasm_ref_t, wasm_val_t\n"
"\n"
"\n"
)
def get_type_name(self, c_type):
if isinstance(c_type, c_ast.TypeDecl):
return self.get_type_name(c_type.type)
elif isinstance(c_type, c_ast.PtrDecl):
pointed_type = self.get_type_name(c_type.type)
if isinstance(c_type.type, c_ast.FuncDecl):
# CFUCNTYPE is a pointer of function
return pointed_type
if "None" == pointed_type:
return "c_void_p"
return f"POINTER({pointed_type})"
elif isinstance(c_type, c_ast.ArrayDecl):
return f"POINTER({self.get_type_name(c_type.type)})"
elif isinstance(c_type, c_ast.IdentifierType):
if len(c_type.names) > 1:
raise RuntimeError(f"unexpected type with a long names: {c_type}")
type_name = c_type.names[0]
if type_name.startswith("wasm_"):
return type_name
if not type_name in self.type_map:
raise RuntimeError(f"a new type should be in type_map: {type_name}")
return self.type_map.get(type_name)
elif isinstance(c_type, c_ast.Union):
if not c_type.name:
raise RuntimeError(f"found an anonymous union {c_type}")
return c_type.name
elif isinstance(c_type, c_ast.Struct):
if not c_type.name:
raise RuntimeError(f"found an anonymous union {c_type}")
return c_type.name
elif isinstance(c_type, c_ast.FuncDecl):
content = "CFUNCTYPE("
if isinstance(c_type.type, c_ast.PtrDecl):
# there is a bug in CFUNCTYPE if the result type is a pointer
content += "c_void_p"
else:
content += f"{self.get_type_name(c_type.type)}"
content += f",{self.get_type_name(c_type.args)}" if c_type.args else ""
content += ")"
return content
elif isinstance(c_type, c_ast.Decl):
return self.get_type_name(c_type.type)
elif isinstance(c_type, c_ast.ParamList):
content = ",".join(
[self.get_type_name(param.type) for param in c_type.params]
)
return content
else:
raise RuntimeError(f"unexpected type: {c_type.show()}")
def visit_Struct(self, node):
# pylint: disable=invalid-name
def gen_fields(info, indent):
content = ""
for k, v in info.items():
content += f'{indent}("{k}", {v}),\n'
return content[:-1]
def gen_equal(info, indent):
content = f"{indent}return"
for k, v in info.items():
# not compare pointer value in __eq__
if v.startswith("POINTER") or v.startswith("c_void_p"):
continue
content += f" self.{k} == other.{k} and"
return content[:-4]
def gen_repr(info, indent):
content = f'{indent}return f"{{{{'
for k, _ in info.items():
content += f"{k}={{self.{k}}}, "
content = content[:-2] + '}}"'
return content
def gen_vector_repr(info, indent):
content = f'{indent}ret = ""\n'
content += f"{indent}for i in range(self.num_elems):\n"
if 1 == info["data"].count("POINTER"):
# pointer
content += f"{2*indent}ret += str(self.data[i])\n"
else:
# pointer of pointer
content += f"{2*indent}ret += str(dereference(self.data[i]))\n"
content += f'{2*indent}ret += " "\n'
content += f"{indent}return ret\n"
return content
if not node.name or not node.name.lower().startswith("wasm"):
return
if node.name in IGNORE_SYMOLS:
return
name = node.name
info = {}
if node.decls:
for decl in node.decls:
info[decl.name] = self.get_type_name(decl.type)
if info:
self.ret += (
f"class {name}(Structure):\n"
f"{INDENT}_fields_ = [\n"
f"{gen_fields(info, INDENT*2)}\n"
f"{INDENT}]\n"
f"\n"
f"{INDENT}def __eq__(self, other):\n"
f"{INDENT*2}if not isinstance(other, {name}):\n"
f"{INDENT*3}return False\n"
f"{gen_equal(info, INDENT*2)}\n"
f"\n"
f"{INDENT}def __repr__(self):\n"
)
self.ret += (
f"{gen_vector_repr(info, INDENT*2)}\n"
if name.endswith("_vec_t")
else f"{gen_repr(info, INDENT*2)}\n"
)
self.ret += "\n"
else:
self.ret += f"class {name}(Structure):\n{INDENT}pass\n"
self.ret += "\n"
def visit_Union(self, node):
# pylint: disable=invalid-name
print(f"Union: {node.show()}")
def visit_Typedef(self, node):
# pylint: disable=invalid-name
# system defined
if not node.name:
return
if not node.name.startswith("wasm_"):
return
if node.name in IGNORE_SYMOLS:
return
self.visit(node.type)
if node.name == self.get_type_name(node.type):
return
else:
self.ret += f"{node.name} = {self.get_type_name(node.type)}\n"
self.ret += "\n"
def visit_FuncDecl(self, node):
# pylint: disable=invalid-name
restype = self.get_type_name(node.type)
if isinstance(node.type, c_ast.TypeDecl):
func_name = node.type.declname
elif isinstance(node.type, c_ast.PtrDecl):
func_name = node.type.type.declname
else:
raise RuntimeError(f"unexpected type in FuncDecl: {type}")
if not func_name.startswith("wasm_") or func_name.endswith("_t"):
return
if func_name in IGNORE_SYMOLS:
return
params_len = 0
for arg in node.args.params:
# ignore void but not void*
if isinstance(arg.type, c_ast.TypeDecl):
type_name = self.get_type_name(arg.type)
if "None" == type_name:
continue
params_len += 1
args = (
"" if not params_len else ",".join([f"arg{i}" for i in range(params_len)])
)
argtypes = f"[{self.get_type_name(node.args)}]" if params_len else "None"
self.ret += (
f"def {func_name}({args}):\n"
f"{INDENT}_{func_name} = libiwasm.{func_name}\n"
f"{INDENT}_{func_name}.restype = {restype}\n"
f"{INDENT}_{func_name}.argtypes = {argtypes}\n"
f"{INDENT}return _{func_name}({args})\n"
)
self.ret += "\n"
def visit_Enum(self, node):
# pylint: disable=invalid-name
elem_value = 0
# generate enum elementes directly as consts with values
for i, elem in enumerate(node.values.enumerators):
self.ret += f"{elem.name}"
if elem.value:
elem_value = int(elem.value.value)
else:
if 0 == i:
elem_value = 0
else:
elem_value += 1
self.ret += f" = {elem_value}\n"
self.ret += "\n"
def preflight_check(workspace):
wamr_repo = workspace.joinpath("wasm-micro-runtime")
file_check_list = [
wamr_repo.exists(),
wamr_repo.joinpath(WASM_C_API_HEADER).exists(),
]
if not all(file_check_list):
print(
"please run utils/download_wamr.py to download the repo, or re-download the repo"
)
return False
if not shutil.which("gcc"):
print("please install gcc")
return False
return True
def do_parse(workspace):
filename = workspace.joinpath(WASM_C_API_HEADER)
filename = str(filename)
ast = parse_file(
filename,
use_cpp=True,
cpp_path="gcc",
cpp_args=[
"-E",
"-D__attribute__(x)=",
"-D__asm__(x)=",
"-D__asm(x)=",
"-D__builtin_va_list=int",
"-D__extension__=",
"-D__inline__=",
"-D__restrict=",
"-D__restrict__=",
"-D_Static_assert(x, y)=",
"-D__signed=",
"-D__volatile__(x)=",
"-Dstatic_assert(x, y)=",
],
)
ast_visitor = Visitor()
ast_visitor.visit(ast)
return ast_visitor.ret
def main():
current_file = pathlib.Path(__file__)
if current_file.is_symlink():
current_file = pathlib.Path(os.readlink(current_file))
current_dir = current_file.parent.resolve()
root_dir = current_dir.joinpath("..").resolve()
if not preflight_check(root_dir):
return False
wamr_repo = root_dir.joinpath("wasm-micro-runtime")
binding_file_path = root_dir.joinpath(BINDING_PATH)
with open(binding_file_path, "wt", encoding="utf-8") as binding_file:
binding_file.write(do_parse(wamr_repo))
return True
if __name__ == "__main__":
sys.exit(0 if main() else 1)

View File

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
__all__ = ["ffi"]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,642 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# pylint: disable=missing-class-docstring
# pylint: disable=missing-function-docstring
# pylint: disable=missing-module-docstring
import ctypes as c
import os
from pathlib import Path
import sys
#
# Prologue. Dependencies of binding
#
# how to open the library file of WAMR
if sys.platform == "linux":
BUILDING_DIR = "product-mini/platforms/linux/build"
LIBRARY_NAME = "libiwasm.so"
elif sys.platform == "win32":
BUILDING_DIR = "product-mini/platforms/windows/build"
LIBRARY_NAME = "iwasm.dll"
elif sys.platform == "darwin":
BUILDING_DIR = "product-mini/platforms/darwin/build"
LIBRARY_NAME = "libiwasm.dylib"
else:
raise RuntimeError(f"unsupported platform `{sys.platform}`")
# FIXME: should load libiwasm.so from current system library path
current_file = Path(__file__)
if current_file.is_symlink():
current_file = Path(os.readlink(current_file))
current_dir = current_file.parent.resolve()
root_dir = current_dir.parent.parent.parent.parent.resolve()
wamr_dir = root_dir.joinpath("wasm-micro-runtime").resolve()
if not wamr_dir.exists():
raise RuntimeError(f"not found the repo of wasm-micro-runtime under {root_dir}")
libpath = wamr_dir.joinpath(BUILDING_DIR).joinpath(LIBRARY_NAME).resolve()
if not libpath.exists():
raise RuntimeError(f"not found precompiled wamr library at {libpath}")
print(f"loading WAMR library from {libpath} ...")
libiwasm = c.cdll.LoadLibrary(libpath)
class wasm_ref_t(c.Structure):
# pylint: disable=invalid-name
pass
class wasm_val_union(c.Union):
# pylint: disable=invalid-name
_fields_ = [
("i32", c.c_int32),
("i64", c.c_int64),
("f32", c.c_float),
("f64", c.c_double),
("ref", c.POINTER(wasm_ref_t)),
]
class wasm_val_t(c.Structure):
# pylint: disable=invalid-name
_fields_ = [
("kind", c.c_uint8),
("of", wasm_val_union),
]
def dereference(p):
# pylint: disable=protected-access
if not isinstance(p, c._Pointer):
raise RuntimeError("not a pointer")
return p.contents
# HELPERs
def create_null_pointer(struct_type):
return c.POINTER(struct_type)()
def is_null_pointer(c_pointer):
# pylint: disable=protected-access
if isinstance(c_pointer, c._Pointer):
return False if c_pointer else True
else:
raise RuntimeError("not a pointer")
def wasm_vec_to_list(vec):
"""
Converts a vector or a POINTER(vector) to a list
vector of type pointers -> list of type pointers
"""
known_vec_type = [
wasm_byte_vec_t,
wasm_valtype_vec_t,
wasm_functype_vec_t,
wasm_globaltype_vec_t,
wasm_tabletype_vec_t,
wasm_memorytype_vec_t,
wasm_externtype_vec_t,
wasm_importtype_vec_t,
wasm_exporttype_vec_t,
wasm_val_vec_t,
wasm_frame_vec_t,
wasm_extern_vec_t,
]
known_vec_pointer_type = [POINTER(type) for type in known_vec_type]
if any([isinstance(vec, type) for type in known_vec_pointer_type]):
vec = dereference(vec)
return [vec.data[i] for i in range(vec.num_elems)]
elif any([isinstance(vec, type) for type in known_vec_type]):
return [vec.data[i] for i in range(vec.num_elems)]
else:
raise RuntimeError("not a known vector type")
def list_to_carray(elem_type, *args):
"""
Converts a python list into a C array
"""
data = (elem_type * len(args))(*args)
return data
def load_module_file(wasm_content):
binary = wasm_byte_vec_t()
wasm_byte_vec_new_uninitialized(binary, len(wasm_content))
# has to use malloced memory.
c.memmove(binary.data, wasm_content, len(wasm_content))
binary.num_elems = len(wasm_content)
return binary
#
# Enhancment of binding
#
from .binding import *
# Built-in functions for Structure
wasm_finalizer = CFUNCTYPE(None, c_void_p)
def __repr_wasm_limits_t(self):
return f"{self.min:#x} {self.max:#x}"
# overwrite
wasm_limits_t.__repr__ = __repr_wasm_limits_t
def __compare_wasm_valtype_t(self, other):
if not isinstance(other, wasm_valtype_t):
return False
return wasm_valtype_kind(byref(self)) == wasm_valtype_kind(byref(other))
def __repr_wasm_valtype_t(self):
val_kind = wasm_valtype_kind(byref(self))
if WASM_I32 == val_kind:
return "i32"
elif WASM_I64 == val_kind:
return "i64"
elif WASM_F32 == val_kind:
return "f32"
elif WASM_F64 == val_kind:
return "f64"
elif WASM_FUNCREF == val_kind:
return "funcref"
else:
return "anyref"
wasm_valtype_t.__eq__ = __compare_wasm_valtype_t
wasm_valtype_t.__repr__ = __repr_wasm_valtype_t
def __compare_wasm_byte_vec_t(self, other):
if not isinstance(other, wasm_byte_vec_t):
return False
if self.num_elems != other.num_elems:
return False
self_data = bytes(self.data[: self.num_elems])
other_data = bytes(other.data[: other.num_elems])
return self_data.decode() == other_data.decode()
def __repr_wasm_byte_vec_t(self):
data = bytes(self.data[: self.num_elems])
return data.decode() if self.size else ""
wasm_byte_vec_t.__eq__ = __compare_wasm_byte_vec_t
wasm_byte_vec_t.__repr__ = __repr_wasm_byte_vec_t
def __compare_wasm_functype_t(self, other):
if not isinstance(other, wasm_functype_t):
return False
params1 = dereference(wasm_functype_params(byref(self)))
params2 = dereference(wasm_functype_params(byref(other)))
results1 = dereference(wasm_functype_results(byref(self)))
results2 = dereference(wasm_functype_results(byref(other)))
return params1 == params2 and results1 == results2
def __repr_wasm_functype_t(self):
params = dereference(wasm_functype_params(byref(self)))
results = dereference(wasm_functype_results(byref(self)))
params = f" (params {params})" if params.size else ""
results = f" (results {results})" if results.size else ""
return f"(func{params}{results})"
wasm_functype_t.__eq__ = __compare_wasm_functype_t
wasm_functype_t.__repr__ = __repr_wasm_functype_t
def __compare_wasm_globaltype_t(self, other):
if not isinstance(other, wasm_globaltype_t):
return False
content1 = dereference(wasm_globaltype_content(byref(self)))
content2 = dereference(wasm_globaltype_content(byref(other)))
mutability1 = wasm_globaltype_mutability(byref(self))
mutability2 = wasm_globaltype_mutability(byref(other))
return content1 == content2 and mutability1 == mutability2
def __repr_wasm_globaltype_t(self):
mutability = f"{wasm_globaltype_mutability(byref(self))}"
content = f"{dereference(wasm_globaltype_content(byref(self)))}"
return f"(global{' mut ' if mutability else ' '}{content})"
wasm_globaltype_t.__eq__ = __compare_wasm_globaltype_t
wasm_globaltype_t.__repr__ = __repr_wasm_globaltype_t
def __compare_wasm_tabletype_t(self, other):
if not isinstance(other, wasm_tabletype_t):
return False
element1 = dereference(wasm_tabletype_element(byref(self)))
element2 = dereference(wasm_tabletype_element(byref(other)))
limits1 = dereference(wasm_tabletype_limits(byref(self)))
limits2 = dereference(wasm_tabletype_limits(byref(other)))
return element1 == element2 and limits1 == limits2
def __repr_wasm_tabletype_t(self):
element = dereference(wasm_tabletype_element(byref(self)))
limit = dereference(wasm_tabletype_limits(byref(self)))
return f"(table {limit} {element})"
wasm_tabletype_t.__eq__ = __compare_wasm_tabletype_t
wasm_tabletype_t.__repr__ = __repr_wasm_tabletype_t
def __compare_wasm_memorytype_t(self, other):
if not isinstance(other, wasm_memorytype_t):
return False
limits1 = dereference(wasm_memorytype_limits(byref(self)))
limits2 = dereference(wasm_memorytype_limits(byref(other)))
return limits1 == limits2
def __repr_wasm_memorytype_t(self):
limit = dereference(wasm_memorytype_limits(byref(self)))
return f"(memory {limit})"
wasm_memorytype_t.__eq__ = __compare_wasm_memorytype_t
wasm_memorytype_t.__repr__ = __repr_wasm_memorytype_t
def __compare_wasm_externtype_t(self, other):
if not isinstance(other, wasm_externtype_t):
return False
if wasm_externtype_kind(byref(self)) != wasm_externtype_kind(byref(other)):
return False
extern_kind = wasm_externtype_kind(byref(self))
if WASM_EXTERN_FUNC == extern_kind:
return dereference(wasm_externtype_as_functype(self)) == dereference(
wasm_externtype_as_functype(other)
)
elif WASM_EXTERN_GLOBAL == extern_kind:
return dereference(wasm_externtype_as_globaltype(self)) == dereference(
wasm_externtype_as_globaltype(other)
)
elif WASM_EXTERN_MEMORY == extern_kind:
return dereference(wasm_externtype_as_memorytype(self)) == dereference(
wasm_externtype_as_memorytype(other)
)
elif WASM_EXTERN_TABLE == extern_kind:
return dereference(wasm_externtype_as_tabletype(self)) == dereference(
wasm_externtype_as_tabletype(other)
)
else:
raise RuntimeError("not a valid wasm_externtype_t")
def __repr_wasm_externtype_t(self):
extern_kind = wasm_externtype_kind(byref(self))
if WASM_EXTERN_FUNC == extern_kind:
return str(dereference(wasm_externtype_as_functype(byref(self))))
elif WASM_EXTERN_GLOBAL == extern_kind:
return str(dereference(wasm_externtype_as_globaltype(byref(self))))
elif WASM_EXTERN_MEMORY == extern_kind:
return str(dereference(wasm_externtype_as_memorytype(byref(self))))
elif WASM_EXTERN_TABLE == extern_kind:
return str(dereference(wasm_externtype_as_tabletype(byref(self))))
else:
raise RuntimeError("not a valid wasm_externtype_t")
wasm_externtype_t.__eq__ = __compare_wasm_externtype_t
wasm_externtype_t.__repr__ = __repr_wasm_externtype_t
def __compare_wasm_importtype_t(self, other):
if not isinstance(other, wasm_importtype_t):
return False
if dereference(wasm_importtype_module(self)) != dereference(
wasm_importtype_module(other)
):
return False
if dereference(wasm_importtype_name(self)) != dereference(
wasm_importtype_name(other)
):
return False
self_type = dereference(wasm_importtype_type(byref(self)))
other_type = dereference(wasm_importtype_type(byref(other)))
return self_type == other_type
def __repr_wasm_importtype_t(self):
module = wasm_importtype_module(byref(self))
name = wasm_importtype_name(byref(self))
extern_type = wasm_importtype_type(byref(self))
return f'(import "{dereference(module)}" "{dereference(name)}" {dereference(extern_type)})'
wasm_importtype_t.__eq__ = __compare_wasm_importtype_t
wasm_importtype_t.__repr__ = __repr_wasm_importtype_t
def __compare_wasm_exporttype_t(self, other):
if not isinstance(other, wasm_exporttype_t):
return False
self_name = dereference(wasm_exporttype_name(byref(self)))
other_name = dereference(wasm_exporttype_name(byref(other)))
if self_name != other_name:
return False
self_type = dereference(wasm_exporttype_type(byref(self)))
other_type = dereference(wasm_exporttype_type(byref(other)))
return self_type == other_type
def __repr_wasm_exporttype_t(self):
name = wasm_exporttype_name(byref(self))
extern_type = wasm_exporttype_type(byref(self))
return f'(export "{dereference(name)}" {dereference(extern_type)})'
wasm_exporttype_t.__eq__ = __compare_wasm_exporttype_t
wasm_exporttype_t.__repr__ = __repr_wasm_exporttype_t
def __compare_wasm_val_t(self, other):
if not isinstance(other, wasm_val_t):
return False
if self.kind != other.kind:
return False
if WASM_I32 == self.kind:
return self.of.i32 == other.of.i32
elif WASM_I64 == self.kind:
return self.of.i64 == other.of.i64
elif WASM_F32 == self.kind:
return self.of.f32 == other.of.f32
elif WASM_F64 == self.kind:
return self.of.f64 == other.of.f63
elif WASM_ANYREF == self.kind:
raise RuntimeError("FIXME")
else:
raise RuntimeError("not a valid val kind")
def __repr_wasm_val_t(self):
if WASM_I32 == self.kind:
return f"i32 {self.of.i32}"
elif WASM_I64 == self.kind:
return f"i64 {self.of.i64}"
elif WASM_F32 == self.kind:
return f"f32 {self.of.f32}"
elif WASM_F64 == self.kind:
return f"f64 {self.of.f64}"
elif WASM_ANYREF == self.kind:
return f"anyref {self.of.ref}"
else:
raise RuntimeError("not a valid val kind")
wasm_val_t.__repr__ = __repr_wasm_val_t
wasm_val_t.__eq__ = __compare_wasm_val_t
def __repr_wasm_trap_t(self):
message = wasm_message_t()
wasm_trap_message(self, message)
return f'(trap "{str(message)}")'
wasm_trap_t.__repr__ = __repr_wasm_trap_t
def __repr_wasm_frame_t(self):
instance = wasm_frame_instance(self)
module_offset = wasm_frame_module_offset(self)
func_index = wasm_frame_func_index(self)
func_offset = wasm_frame_func_offset(self)
return f"> module:{module_offset:#x} => func#{func_index:#x}.{func_offset:#x}"
wasm_frame_t.__repr__ = __repr_wasm_frame_t
def __repr_wasm_module_t(self):
imports = wasm_importtype_vec_t()
wasm_module_imports(self, imports)
exports = wasm_exporttype_vec_t()
wasm_module_exports(self, exports)
ret = "(module"
ret += str(imports).replace("(import", "\n (import")
ret += str(exports).replace("(export", "\n (export")
ret += "\n)"
return ret
wasm_module_t.__repr__ = __repr_wasm_module_t
def __repr_wasm_instance_t(self):
exports = wasm_extern_vec_t()
wasm_instance_exports(self, exports)
ret = "(instance"
ret += str(exports).replace("(export", "\n (export")
ret += "\n)"
return ret
wasm_instance_t.__repr__ = __repr_wasm_instance_t
def __repr_wasm_func_t(self):
ft = wasm_func_type(self)
return f"{str(dereference(ft))[:-1]} ... )"
wasm_func_t.__repr__ = __repr_wasm_func_t
def __repr_wasm_global_t(self):
gt = wasm_global_type(self)
return f"{str(dereference(gt))[:-1]} ... )"
wasm_global_t.__repr__ = __repr_wasm_global_t
def __repr_wasm_table_t(self):
tt = wasm_table_type(self)
return f"{str(dereference(tt))[:-1]} ... )"
wasm_table_t.__repr__ = __repr_wasm_table_t
def __repr_wasm_memory_t(self):
mt = wasm_memory_type(self)
return f"{str(dereference(mt))[:-1]} ... )"
wasm_memory_t.__repr__ = __repr_wasm_memory_t
def __repr_wasm_extern_t(self):
ext_type = wasm_extern_type(self)
ext_kind = wasm_extern_kind(self)
ret = "(export "
if WASM_EXTERN_FUNC == ext_kind:
ft = wasm_externtype_as_functype(ext_type)
ret += str(dereference(ft))
elif WASM_EXTERN_GLOBAL == ext_kind:
gt = wasm_externtype_as_globaltype(ext_type)
ret += str(dereference(gt))
elif WASM_EXTERN_MEMORY == ext_kind:
mt = wasm_externtype_as_memorytype(ext_type)
ret += str(dereference(mt))
elif WASM_EXTERN_TABLE == ext_kind:
tt = wasm_externtype_as_tabletype(ext_type)
ret += str(dereference(tt))
else:
raise RuntimeError("not a valid extern kind")
ret += ")"
return ret
wasm_extern_t.__repr__ = __repr_wasm_extern_t
# Function Types construction short-hands
def wasm_name_new_from_string(s):
name = wasm_name_t()
data = ((c.c_ubyte) * len(s)).from_buffer_copy(s.encode())
wasm_byte_vec_new(byref(name), len(s), data)
return name
def __wasm_functype_new(param_list, result_list):
def __list_to_wasm_valtype_vec(l):
vec = wasm_valtype_vec_t()
if not l:
wasm_valtype_vec_new_empty(byref(vec))
else:
data_type = POINTER(wasm_valtype_t) * len(l)
data = data_type()
for i in range(len(l)):
data[i] = l[i]
wasm_valtype_vec_new(byref(vec), len(l), data)
return vec
params = __list_to_wasm_valtype_vec(param_list)
results = __list_to_wasm_valtype_vec(result_list)
return wasm_functype_new(byref(params), byref(results))
def wasm_functype_new_0_0():
return __wasm_functype_new([], [])
def wasm_functype_new_1_0(p1):
return __wasm_functype_new([p1], [])
def wasm_functype_new_2_0(p1, p2):
return __wasm_functype_new([p1, p2], [])
def wasm_functype_new_3_0(p1, p2, p3):
return __wasm_functype_new([p1, p2, p3], [])
def wasm_functype_new_0_1(r1):
return __wasm_functype_new([], [r1])
def wasm_functype_new_1_1(p1, r1):
return __wasm_functype_new([p1], [r1])
def wasm_functype_new_2_1(p1, p2, r1):
return __wasm_functype_new([p1, p2], [r1])
def wasm_functype_new_3_1(p1, p2, p3, r1):
return __wasm_functype_new([p1, p2, p3], [r1])
def wasm_limits_new(min, max):
limit = wasm_limits_t()
limit.min = min
limit.max = max
return c.pointer(limit)
def wasm_i32_val(i):
v = wasm_val_t()
v.kind = WASM_I32
v.of.i32 = i
return v
def wasm_i64_val(i):
v = wasm_val_t()
v.kind = WASM_I64
v.of.i64 = i
return v
def wasm_f32_val(z):
v = wasm_val_t()
v.kind = WASM_F32
v.of.f32 = z
return v
def wasm_f64_val(z):
v = wasm_val_t()
v.kind = WASM_F64
v.of.f64 = z
return v
def wasm_func_cb_decl(func):
return wasm_func_callback_t(func)
def wasm_func_with_env_cb_decl(func):
return wasm_func_callback_with_env_t(func)

View File

@ -160,6 +160,12 @@ else
CFLAGS += -DWASM_ENABLE_BULK_MEMORY=0
endif
ifeq ($(CONFIG_INTERPRETERS_WAMR_PERF_PROFILING),y)
CFLAGS += -DWASM_ENABLE_PERF_PROFILING=1
else
CFLAGS += -DWASM_ENABLE_PERF_PROFILING=0
endif
ifeq ($(CONFIG_INTERPRETERS_WAMR_MEMORY_PROFILING),y)
CFLAGS += -DWASM_ENABLE_MEMORY_PROFILING=1
else
@ -174,10 +180,27 @@ endif
ifeq ($(CONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN),y)
CFLAGS += -DWASM_ENABLE_LIBC_BUILTIN=1
CSRCS += libc_builtin_wrapper.c
VPATH += $(IWASM_ROOT)/libraries/libc-builtin
else
CFLAGS += -DWASM_ENABLE_LIBC_BUILTIN=0
endif
ifeq ($(CONFIG_INTERPRETERS_WAMR_LIBC_WASI),y)
CFLAGS += -DWASM_ENABLE_LIBC_WASI=1
CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/src
CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/include
CSRCS += posix_socket.c
CSRCS += libc_wasi_wrapper.c
VPATH += $(IWASM_ROOT)/libraries/libc-wasi
CSRCS += posix.c
CSRCS += random.c
CSRCS += str.c
VPATH += $(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/src
else
CFLAGS += -DWASM_ENABLE_LIBC_WASI=0
endif
ifeq ($(CONFIG_INTERPRETERS_WAMR_MULTI_MODULE),y)
CFLAGS += -DWASM_ENABLE_MULTI_MODULE=1
else
@ -253,7 +276,6 @@ CSRCS += nuttx_platform.c \
bh_vector.c \
bh_read_file.c \
runtime_timer.c \
libc_builtin_wrapper.c \
wasm_application.c \
wasm_runtime_common.c \
wasm_native.c \
@ -272,7 +294,6 @@ VPATH += $(SHARED_ROOT)/utils/uncommon
VPATH += $(IWASM_ROOT)/common
VPATH += $(IWASM_ROOT)/interpreter
VPATH += $(IWASM_ROOT)/libraries
VPATH += $(IWASM_ROOT)/libraries/libc-builtin
VPATH += $(IWASM_ROOT)/libraries/lib-pthread
VPATH += $(IWASM_ROOT)/common/arch
VPATH += $(IWASM_ROOT)/aot

View File

@ -98,7 +98,7 @@ app_instance_func(wasm_module_inst_t module_inst, const char *func_name)
static char **
split_string(char *str, int *count)
{
char **res = NULL;
char **res = NULL, **res1;
char *p;
int idx = 0;
@ -106,16 +106,18 @@ split_string(char *str, int *count)
do {
p = strtok(str, " ");
str = NULL;
res = (char **)realloc(res, sizeof(char *) * (uint32)(idx + 1));
res1 = res;
res = (char **)realloc(res1, sizeof(char *) * (uint32)(idx + 1));
if (res == NULL) {
free(res1);
return NULL;
}
res[idx++] = p;
} while (p);
/**
* since the function name,
* res[0] might be contains a '\' to indicate a space
* Due to the function name,
* res[0] might contain a '\' to indicate a space
* func\name -> func name
*/
p = strchr(res[0], '\\');

View File

@ -84,7 +84,7 @@ app_instance_func(wasm_module_inst_t module_inst, const char *func_name)
static char **
split_string(char *str, int *count)
{
char **res = NULL;
char **res = NULL, **res1;
char *p, *next_token;
int idx = 0;
@ -92,16 +92,18 @@ split_string(char *str, int *count)
do {
p = strtok_s(str, " ", &next_token);
str = NULL;
res = (char **)realloc(res, sizeof(char *) * (uint32)(idx + 1));
res1 = res;
res = (char **)realloc(res1, sizeof(char *) * (uint32)(idx + 1));
if (res == NULL) {
free(res1);
return NULL;
}
res[idx++] = p;
} while (p);
/**
* since the function name,
* res[0] might be contains a '\' to indicate a space
* Due to the function name,
* res[0] might contain a '\' to indicate a space
* func\name -> func name
*/
p = strchr(res[0], '\\');

View File

@ -1,387 +0,0 @@
Copyright (C) Joel Martin <github@martintribe.org>
The wac project is licensed under the MPL 2.0 (Mozilla Public License
2.0). The text of the MPL 2.0 license is included below and can be
found at https://www.mozilla.org/MPL/2.0/
By default, wac and wace link with the BSD licensed editline library
(http://www.thrysoee.dk/editline/). The wac/wace build process can be
switched to link with the GPL license GNU readline library with the
USE_READLINE=1 flag.
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

View File

@ -57,26 +57,25 @@ rundir = None
class Runner():
def __init__(self, args, no_pty=False):
#print "args: %s" % repr(args)
self.no_pty = no_pty
# Cleanup child process on exit
atexit.register(self.cleanup)
self.p = None
self.process = None
env = os.environ
env['TERM'] = 'dumb'
env['INPUTRC'] = '/dev/null'
env['PERL_RL'] = 'false'
if no_pty:
self.p = Popen(args, bufsize=0,
self.process = Popen(args, bufsize=0,
stdin=PIPE, stdout=PIPE, stderr=STDOUT,
preexec_fn=os.setsid,
env=env)
self.stdin = self.p.stdin
self.stdout = self.p.stdout
self.stdin = self.process.stdin
self.stdout = self.process.stdout
else:
# provide tty to get 'interactive' readline to work
# Use tty to setup an interactive environment
master, slave = pty.openpty()
# Set terminal size large so that readline will not send
@ -84,7 +83,7 @@ class Runner():
buf = array.array('h', [100, 200, 0, 0])
fcntl.ioctl(master, termios.TIOCSWINSZ, buf, True)
self.p = Popen(args, bufsize=0,
self.process = Popen(args, bufsize=0,
stdin=slave, stdout=slave, stderr=STDOUT,
preexec_fn=os.setsid,
env=env)
@ -95,55 +94,55 @@ class Runner():
self.stdin = os.fdopen(master, 'r+b', 0)
self.stdout = self.stdin
#print "started"
self.buf = ""
self.last_prompt = ""
def read_to_prompt(self, prompts, timeout):
end_time = time.time() + timeout
while time.time() < end_time:
wait_until = time.time() + timeout
while time.time() < wait_until:
[outs,_,_] = select([self.stdout], [], [], 1)
if self.stdout in outs:
new_data = self.stdout.read(1)
if not new_data:
read_byte = self.stdout.read(1)
if not read_byte:
# EOF on macOS ends up here.
break
new_data = new_data.decode("utf-8") if IS_PY_3 else new_data
#print("new_data: '%s'" % new_data)
debug(new_data)
read_byte = read_byte.decode('utf-8') if IS_PY_3 else read_byte
debug(read_byte)
if self.no_pty:
self.buf += new_data.replace("\n", "\r\n")
self.buf += read_byte.replace('\n', '\r\n')
else:
self.buf += new_data
self.buf = self.buf.replace("\r\r", "\r")
self.buf += read_byte
self.buf = self.buf.replace('\r\r', '\r')
# filter the prompts
for prompt in prompts:
regexp = re.compile(prompt)
match = regexp.search(self.buf)
pattern = re.compile(prompt)
match = pattern.search(self.buf)
if match:
end = match.end()
buf = self.buf[0:end-len(prompt)]
self.buf = self.buf[end:]
self.last_prompt = prompt
return buf
return None
def writeline(self, str):
def _to_bytes(s):
return bytes(s, "utf-8") if IS_PY_3 else s
str_to_write = str + '\n'
str_to_write = bytes(
str_to_write, 'utf-8') if IS_PY_3 else str_to_write
self.stdin.write(_to_bytes(str + "\n"))
self.stdin.write(str_to_write)
def cleanup(self):
if self.p:
if self.process:
try:
self.writeline("__exit__")
time.sleep(.020)
os.killpg(self.p.pid, signal.SIGTERM)
self.process.kill()
except OSError:
pass
except IOError:
pass
self.p = None
self.process = None
self.stdin.close()
if self.stdin != self.stdout:
self.stdout.close()

View File

@ -35,11 +35,16 @@ add_definitions(-DWASM_ENABLE_REF_TYPES=1)
add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1)
add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1)
add_definitions(-DWASM_ENABLE_PERF_PROFILING=1)
add_definitions(-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)
if (WAMR_BUILD_LLVM_LEGACY_PM EQUAL 1)
add_definitions(-DWASM_ENABLE_LLVM_LEGACY_PM=1)
endif()
if (DEFINED WAMR_BUILD_AOT_FUNC_PREFIX)
add_definitions(-DAOT_FUNC_PREFIX="${WAMR_BUILD_AOT_FUNC_PREFIX}")
endif ()
# Set WAMR_BUILD_TARGET, currently values supported:
# "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32"
if (NOT WAMR_BUILD_TARGET)

View File

@ -10,7 +10,7 @@
#include "aot_export.h"
/* clang-format off */
static int
static void
print_help()
{
printf("Usage: wamrc [options] -o output_file wasm_file\n");
@ -58,14 +58,66 @@ print_help()
printf(" --enable-indirect-mode Enalbe call function through symbol table but not direct call\n");
printf(" --disable-llvm-intrinsics Disable the LLVM built-in intrinsics\n");
printf(" --disable-llvm-lto Disable the LLVM link time optimization\n");
printf(" --emit-custom-sections=<section names>\n");
printf(" Emit the specified custom sections to AoT file, using comma to separate\n");
printf(" multiple names, e.g.\n");
printf(" --emit-custom-sections=section1,section2,sectionN\n");
printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n");
printf("Examples: wamrc -o test.aot test.wasm\n");
printf(" wamrc --target=i386 -o test.aot test.wasm\n");
printf(" wamrc --target=i386 --format=object -o test.o test.wasm\n");
return 1;
}
/* clang-format on */
#define PRINT_HELP_AND_EXIT() \
do { \
print_help(); \
goto fail0; \
} while (0)
/**
* Split a strings into an array of strings
* Returns NULL on failure
* Memory must be freed by caller
* Based on: http://stackoverflow.com/a/11198630/471795
*/
static char **
split_string(char *str, int *count, const char *delimer)
{
char **res = NULL, **res1;
char *p;
int idx = 0;
/* split string and append tokens to 'res' */
do {
p = strtok(str, delimer);
str = NULL;
res1 = res;
res = (char **)realloc(res1, sizeof(char *) * (uint32)(idx + 1));
if (res == NULL) {
free(res1);
return NULL;
}
res[idx++] = p;
} while (p);
/**
* Due to the section name,
* res[0] might contain a '\' to indicate a space
* func\name -> func name
*/
p = strchr(res[0], '\\');
while (p) {
*p = ' ';
p = strchr(p, '\\');
}
if (count) {
*count = idx - 1;
}
return res;
}
int
main(int argc, char *argv[])
{
@ -97,39 +149,39 @@ main(int argc, char *argv[])
if (!strcmp(argv[0], "-o")) {
argc--, argv++;
if (argc < 2)
return print_help();
PRINT_HELP_AND_EXIT();
out_file_name = argv[0];
}
else if (!strncmp(argv[0], "--target=", 9)) {
if (argv[0][9] == '\0')
return print_help();
PRINT_HELP_AND_EXIT();
option.target_arch = argv[0] + 9;
}
else if (!strncmp(argv[0], "--target-abi=", 13)) {
if (argv[0][13] == '\0')
return print_help();
PRINT_HELP_AND_EXIT();
option.target_abi = argv[0] + 13;
}
else if (!strncmp(argv[0], "--cpu=", 6)) {
if (argv[0][6] == '\0')
return print_help();
PRINT_HELP_AND_EXIT();
option.target_cpu = argv[0] + 6;
}
else if (!strncmp(argv[0], "--cpu-features=", 15)) {
if (argv[0][15] == '\0')
return print_help();
PRINT_HELP_AND_EXIT();
option.cpu_features = argv[0] + 15;
}
else if (!strncmp(argv[0], "--opt-level=", 12)) {
if (argv[0][12] == '\0')
return print_help();
PRINT_HELP_AND_EXIT();
option.opt_level = (uint32)atoi(argv[0] + 12);
if (option.opt_level > 3)
option.opt_level = 3;
}
else if (!strncmp(argv[0], "--size-level=", 13)) {
if (argv[0][13] == '\0')
return print_help();
PRINT_HELP_AND_EXIT();
option.size_level = (uint32)atoi(argv[0] + 13);
if (option.size_level > 3)
option.size_level = 3;
@ -143,7 +195,7 @@ main(int argc, char *argv[])
}
else if (!strncmp(argv[0], "--format=", 9)) {
if (argv[0][9] == '\0')
return print_help();
PRINT_HELP_AND_EXIT();
if (!strcmp(argv[0] + 9, "aot"))
option.output_format = AOT_FORMAT_FILE;
else if (!strcmp(argv[0] + 9, "object"))
@ -154,13 +206,13 @@ main(int argc, char *argv[])
option.output_format = AOT_LLVMIR_OPT_FILE;
else {
printf("Invalid format %s.\n", argv[0] + 9);
return print_help();
PRINT_HELP_AND_EXIT();
}
}
else if (!strncmp(argv[0], "-v=", 3)) {
log_verbose_level = atoi(argv[0] + 3);
if (log_verbose_level < 0 || log_verbose_level > 5)
return print_help();
PRINT_HELP_AND_EXIT();
}
else if (!strcmp(argv[0], "--disable-bulk-memory")) {
option.enable_bulk_memory = false;
@ -201,12 +253,27 @@ main(int argc, char *argv[])
else if (!strcmp(argv[0], "--disable-llvm-lto")) {
option.disable_llvm_lto = true;
}
else if (!strncmp(argv[0], "--emit-custom-sections=", 23)) {
int len = 0;
if (option.custom_sections) {
free(option.custom_sections);
}
option.custom_sections = split_string(argv[0] + 23, &len, ",");
if (!option.custom_sections) {
printf("Failed to process emit-custom-sections: alloc "
"memory failed\n");
PRINT_HELP_AND_EXIT();
}
option.custom_sections_count = len;
}
else
return print_help();
PRINT_HELP_AND_EXIT();
}
if (argc == 0 || !out_file_name)
return print_help();
PRINT_HELP_AND_EXIT();
if (!size_level_set) {
/**
@ -348,6 +415,12 @@ fail1:
/* Destroy runtime environment */
wasm_runtime_destroy();
fail0:
/* free option.custom_sections */
if (option.custom_sections) {
free(option.custom_sections);
}
bh_print_time("wamrc return");
return exit_status;
}