mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-03-12 00:45:28 +00:00
Merge pull request #2426 from bytecodealliance/main
Merge branch main into dev/wasi-libc-windows
This commit is contained in:
commit
a07d8160f9
|
@ -1,20 +1,21 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp/.devcontainer/base.Dockerfile
|
||||
# [Choice] Debian / Ubuntu version (use Debian 11/9, Ubuntu 18.04/21.04 on local arm64/Apple Silicon): debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
|
||||
ARG VARIANT=ubuntu-20.04
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT}
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/cpp/.devcontainer/base.Dockerfile
|
||||
# [Choice] Debian / Ubuntu version (use Debian 12/11/9, Ubuntu 18.04/21.04 on local arm64/Apple Silicon): debian-12, debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
|
||||
ARG VARIANT=debian-12
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/cpp:${VARIANT}
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Asian/Shanghai
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get install -y apt-transport-https apt-utils build-essential \
|
||||
ca-certificates ccache curl g++-multilib git gnupg \
|
||||
libgcc-9-dev lib32gcc-9-dev lsb-release \
|
||||
ninja-build ocaml ocamlbuild python2.7 \
|
||||
ca-certificates ccache cmake curl g++-multilib git gnupg \
|
||||
libgcc-12-dev lib32gcc-12-dev lsb-release \
|
||||
ninja-build ocaml ocamlbuild \
|
||||
software-properties-common tree tzdata \
|
||||
unzip valgrind vim wget zip --no-install-recommends \
|
||||
&& apt-get clean -y \
|
||||
|
@ -22,32 +23,32 @@ RUN apt-get update \
|
|||
|
||||
#
|
||||
# binaryen
|
||||
ARG BINARYEN_VER=111
|
||||
ARG BINARYEN_VER=114
|
||||
WORKDIR /opt
|
||||
RUN wget -c --progress=dot:giga https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VER}/binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz \
|
||||
&& tar xf binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz \
|
||||
&& ln -sf /opt/binaryen-version_111 /opt/binaryen \
|
||||
&& ln -sf /opt/binaryen-version_${BINARYEN_VER} /opt/binaryen \
|
||||
&& rm binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz
|
||||
|
||||
#
|
||||
# CMAKE (https://apt.kitware.com/)
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
# hadolint ignore=DL3008
|
||||
RUN wget --progress=dot:giga -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \
|
||||
&& echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null \
|
||||
&& apt-get update \
|
||||
&& rm /usr/share/keyrings/kitware-archive-keyring.gpg \
|
||||
&& apt-get install -y kitware-archive-keyring --no-install-recommends \
|
||||
&& apt-get install -y cmake --no-install-recommends \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
ARG CMAKE_VER=3.27.0
|
||||
RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh \
|
||||
-q -O /tmp/cmake-install.sh \
|
||||
&& chmod u+x /tmp/cmake-install.sh \
|
||||
&& mkdir /opt/cmake-${CMAKE_VER} \
|
||||
&& /tmp/cmake-install.sh --skip-license --prefix=/opt/cmake-${CMAKE_VER} \
|
||||
&& rm /tmp/cmake-install.sh \
|
||||
&& ln -s /opt/cmake-${CMAKE_VER}/bin/* /usr/local/bin
|
||||
|
||||
#
|
||||
# install emsdk
|
||||
WORKDIR /opt
|
||||
RUN git clone https://github.com/emscripten-core/emsdk.git
|
||||
|
||||
ARG EMSDK_VER=3.0.0
|
||||
ARG EMSDK_VER=3.1.43
|
||||
WORKDIR /opt/emsdk
|
||||
RUN git pull \
|
||||
&& ./emsdk install ${EMSDK_VER} \
|
||||
|
@ -56,7 +57,7 @@ RUN git pull \
|
|||
|
||||
#
|
||||
# install wasi-sdk
|
||||
ARG WASI_SDK_VER=19
|
||||
ARG WASI_SDK_VER=20
|
||||
RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt \
|
||||
&& tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \
|
||||
&& ln -sf /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \
|
||||
|
@ -64,7 +65,7 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases
|
|||
|
||||
#
|
||||
#install wabt
|
||||
ARG WABT_VER=1.0.29
|
||||
ARG WABT_VER=1.0.33
|
||||
RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz -P /opt \
|
||||
&& tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \
|
||||
&& ln -sf /opt/wabt-${WABT_VER} /opt/wabt \
|
||||
|
@ -72,7 +73,7 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/dow
|
|||
|
||||
#
|
||||
# install bazelisk
|
||||
ARG BAZELISK_VER=1.12.0
|
||||
ARG BAZELISK_VER=1.17.0
|
||||
RUN mkdir /opt/bazelisk \
|
||||
&& wget -c --progress=dot:giga https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 -P /opt/bazelisk \
|
||||
&& chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \
|
||||
|
@ -80,16 +81,30 @@ RUN mkdir /opt/bazelisk \
|
|||
|
||||
#
|
||||
# install clang+llvm
|
||||
ARG LLVM_VER=14
|
||||
RUN apt-get purge -y clang-10 llvm-10 && apt-get autoremove -y
|
||||
ARG LLVM_VER=16
|
||||
RUN apt-get purge -y clang-14 llvm-14 && apt-get autoremove -y
|
||||
WORKDIR /etc/apt/apt.conf.d
|
||||
RUN touch 99verfiy-peer.conf \
|
||||
&& echo "Acquire { https::Verify-Peer false }" > 99verfiy-peer.conf
|
||||
|
||||
WORKDIR /tmp
|
||||
RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \
|
||||
&& chmod a+x ./llvm.sh \
|
||||
&& ./llvm.sh ${LLVM_VER} all
|
||||
#RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \
|
||||
# && chmod a+x ./llvm.sh \
|
||||
# && ./llvm.sh ${LLVM_VER} all
|
||||
|
||||
# Workaround due to https://github.com/llvm/llvm-project/issues/62475
|
||||
# hadolint ignore=DL3008
|
||||
RUN set -ex \
|
||||
&& echo "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-${LLVM_VER} main" > /etc/apt/sources.list.d/apt.llvm.org.list \
|
||||
&& wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y \
|
||||
clang-${LLVM_VER} lldb-${LLVM_VER} lld-${LLVM_VER} clangd-${LLVM_VER} clang-tidy-${LLVM_VER} clang-format-${LLVM_VER} clang-tools-${LLVM_VER} \
|
||||
llvm-${LLVM_VER}-dev lld-${LLVM_VER} lldb-${LLVM_VER} llvm-${LLVM_VER}-tools libomp-${LLVM_VER}-dev libc++-${LLVM_VER}-dev libc++abi-${LLVM_VER}-dev \
|
||||
libclang-common-${LLVM_VER}-dev libclang-${LLVM_VER}-dev libclang-cpp${LLVM_VER}-dev libunwind-${LLVM_VER}-dev \
|
||||
libclang-rt-${LLVM_VER}-dev libpolly-${LLVM_VER}-dev --no-install-recommends \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
#
|
||||
# [Optional]
|
||||
|
@ -105,18 +120,19 @@ RUN apt-get update \
|
|||
#
|
||||
# Install required python packages
|
||||
# hadolint ignore=DL3013
|
||||
RUN python3 -m pip install --no-cache-dir --upgrade pip \
|
||||
&& pip3 install --no-cache-dir black nose pycparser pylint
|
||||
RUN python3 -m pip install --no-cache-dir --break-system-packages --upgrade pip \
|
||||
&& pip3 install --no-cache-dir --break-system-packages black nose pycparser pylint
|
||||
|
||||
#
|
||||
# Install github-cli. It doens't work as a feature of devcontainer.json
|
||||
ARG GH_CLI_VER=2.32.0
|
||||
WORKDIR /tmp
|
||||
RUN wget -q https://github.com/cli/cli/releases/download/v2.20.2/gh_2.20.2_linux_amd64.deb \
|
||||
&& dpkg -i gh_2.20.2_linux_amd64.deb
|
||||
RUN wget -q https://github.com/cli/cli/releases/download/v${GH_CLI_VER}/gh_${GH_CLI_VER}_linux_amd64.deb \
|
||||
&& dpkg -i gh_${GH_CLI_VER}_linux_amd64.deb
|
||||
|
||||
#
|
||||
# Install NodeJS
|
||||
RUN wget -qO- https://deb.nodesource.com/setup_19.x | bash -
|
||||
RUN wget -qO- https://deb.nodesource.com/setup_20.x | bash -
|
||||
# hadolint ignore=DL3008
|
||||
RUN apt-get install -y nodejs --no-install-recommends
|
||||
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
// Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/cpp
|
||||
{
|
||||
"name": "WAMR-Dev",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
// Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
|
||||
// Use Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon
|
||||
// Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-12, debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
|
||||
// Use Debian 12, Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon
|
||||
"args": {
|
||||
"BINARYEN_VER": "111",
|
||||
"EMSDK_VER": "3.0.0",
|
||||
"LLVM_VER": "15",
|
||||
"VARIANT": "ubuntu-20.04",
|
||||
"WASI_SDK_VER": "19",
|
||||
"WABT_VER": "1.0.31"
|
||||
"BINARYEN_VER": "114",
|
||||
"BAZELISK_VER": "1.17.0",
|
||||
"CMAKE_VER": "3.27.0",
|
||||
"EMSDK_VER": "3.1.43",
|
||||
"GH_CLI_VER": "2.32.0",
|
||||
"LLVM_VER": "16",
|
||||
"VARIANT": "debian-12",
|
||||
"WASI_SDK_VER": "20",
|
||||
"WABT_VER": "1.0.33"
|
||||
}
|
||||
},
|
||||
"runArgs": [
|
||||
|
@ -34,7 +37,7 @@
|
|||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"ms-vscode.cmake-tools",
|
||||
"ms-vscode.cmake-tools"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -527,7 +527,7 @@ jobs:
|
|||
working-directory: ./core/iwasm/libraries/lib-socket/test/
|
||||
|
||||
- name: run tests
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 20
|
||||
run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
|
||||
working-directory: ./tests/wamr-test-suites
|
||||
|
||||
|
@ -543,7 +543,7 @@ jobs:
|
|||
sudo apt install -y g++-multilib lib32gcc-9-dev
|
||||
|
||||
- name: run tests x86_32
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 20
|
||||
if: env.TEST_ON_X86_32 == 'true'
|
||||
run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
|
||||
working-directory: ./tests/wamr-test-suites
|
||||
|
|
47
.github/workflows/hadolint_dockerfiles.yml
vendored
Normal file
47
.github/workflows/hadolint_dockerfiles.yml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
name: hadolint dockerfiles
|
||||
|
||||
on:
|
||||
# will be triggered on PR events
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
paths:
|
||||
- "**/Dockerfile*"
|
||||
- ".github/workflows/hadolint_dockerfiles.yml"
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "dev/**"
|
||||
paths:
|
||||
- "**/Dockerfile*"
|
||||
- ".github/workflows/hadolint_dockerfiles.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
|
||||
|
||||
jobs:
|
||||
run-hadolint-on-dockerfiles:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# on default, hadolint will fail on warnings and errors
|
||||
- name: Run hadolint on dockerfiles
|
||||
run: |
|
||||
docker pull hadolint/hadolint:latest-debian
|
||||
find . -name "*Dockerfile*" | while read dockerfile; do
|
||||
echo "run hadolint on $dockerfile:"
|
||||
docker run --rm -i hadolint/hadolint:latest-debian hadolint - <"$dockerfile"
|
||||
echo "successful"
|
||||
done
|
4
.github/workflows/nightly_run.yml
vendored
4
.github/workflows/nightly_run.yml
vendored
|
@ -595,7 +595,7 @@ jobs:
|
|||
working-directory: ./core/iwasm/libraries/lib-socket/test/
|
||||
|
||||
- name: run tests
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 20
|
||||
run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
|
||||
working-directory: ./tests/wamr-test-suites
|
||||
|
||||
|
@ -611,7 +611,7 @@ jobs:
|
|||
sudo apt install -y g++-multilib lib32gcc-9-dev
|
||||
|
||||
- name: run tests x86_32
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 20
|
||||
if: env.TEST_ON_X86_32 == 'true'
|
||||
run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }}
|
||||
working-directory: ./tests/wamr-test-suites
|
|
@ -22,7 +22,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the
|
|||
|
||||
| third party components | version number | latest release | vendor pages | CVE details |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| cjson | 1.7.10 | 1.7.14 | https://github.com/DaveGamble/cJSON | https://www.cvedetails.com/vendor/19164/Cjson-Project.html |
|
||||
| cjson | 1.7.16 | 1.7.16 | https://github.com/DaveGamble/cJSON | https://www.cvedetails.com/vendor/19164/Cjson-Project.html |
|
||||
| contiki-ng (er-coap) | unspecified | 3.0 | https://github.com/contiki-os/contiki | https://www.cvedetails.com/vendor/16528/Contiki-os.html |
|
||||
| freebsd libm | unspecified | 13.0 | https://www.freebsd.org/ | https://www.cvedetails.com/vendor/6/Freebsd.html |
|
||||
| LVGL | 6.0.1 | 7.11.0 | https://lvgl.io/ | |
|
||||
|
@ -31,7 +31,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the
|
|||
| wasmtime | unspecified | v0.26.0 | https://github.com/bytecodealliance/wasmtime | |
|
||||
| zephyr | unspecified | v2.5.0 | https://www.zephyrproject.org/ | https://www.cvedetails.com/vendor/19255/Zephyrproject.html |
|
||||
| WebAssembly debugging patch for LLDB | unspecified | unspecified | https://reviews.llvm.org/D78801 | |
|
||||
| libuv | v1.42.0 | v1.44.1 | https://github.com/libuv/libuv | https://www.cvedetails.com/vendor/15402/Libuv-Project.html |
|
||||
| libuv | v1.46.0 | v1.46.0 | https://github.com/libuv/libuv | https://www.cvedetails.com/vendor/15402/Libuv-Project.html |
|
||||
| uvwasi | unspecified | v0.0.12 | https://github.com/nodejs/uvwasi | |
|
||||
| asmjit | unspecified | unspecified | https://github.com/asmjit/asmjit | |
|
||||
| zydis | unspecified | e14a07895136182a5b53e181eec3b1c6e0b434de | https://github.com/zyantific/zydis | |
|
||||
|
|
|
@ -461,4 +461,15 @@
|
|||
#define WASM_CONFIGURABLE_BOUNDS_CHECKS 0
|
||||
#endif
|
||||
|
||||
/* Some chip cannot support external ram with rwx attr at the same time,
|
||||
it has to map it into 2 spaces of idbus and dbus, code in dbus can be
|
||||
read/written and read/executed in ibus. so there are 2 steps to execute
|
||||
the code, first, copy&do relocaiton in dbus space, and second execute
|
||||
it in ibus space, since in the 2 spaces the contents are the same,
|
||||
so we call it bus mirror.
|
||||
*/
|
||||
#ifndef WASM_MEM_DUAL_BUS_MIRROR
|
||||
#define WASM_MEM_DUAL_BUS_MIRROR 0
|
||||
#endif
|
||||
|
||||
#endif /* end of _CONFIG_H_ */
|
||||
|
|
|
@ -3013,6 +3013,9 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size,
|
|||
uint32 section_size;
|
||||
uint64 total_size;
|
||||
uint8 *aot_text;
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
uint8 *mirrored_text;
|
||||
#endif
|
||||
|
||||
if (!resolve_execute_mode(buf, size, &is_indirect_mode, error_buf,
|
||||
error_buf_size)) {
|
||||
|
@ -3071,8 +3074,17 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size,
|
|||
bh_assert((uintptr_t)aot_text < INT32_MAX);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
mirrored_text = os_get_dbus_mirror(aot_text);
|
||||
bh_assert(mirrored_text != NULL);
|
||||
bh_memcpy_s(mirrored_text, (uint32)total_size,
|
||||
section->section_body, (uint32)section_size);
|
||||
os_dcache_flush();
|
||||
#else
|
||||
bh_memcpy_s(aot_text, (uint32)total_size,
|
||||
section->section_body, (uint32)section_size);
|
||||
#endif
|
||||
section->section_body = aot_text;
|
||||
destroy_aot_text = true;
|
||||
|
||||
|
|
|
@ -339,11 +339,8 @@ memories_deinstantiate(AOTModuleInstance *module_inst)
|
|||
memory_inst = module_inst->memories[i];
|
||||
if (memory_inst) {
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (memory_inst->is_shared) {
|
||||
int32 ref_count = shared_memory_dec_reference(
|
||||
(WASMModuleCommon *)module_inst->module);
|
||||
bh_assert(ref_count >= 0);
|
||||
|
||||
if (shared_memory_is_shared(memory_inst)) {
|
||||
uint32 ref_count = shared_memory_dec_reference(memory_inst);
|
||||
/* if the reference count is not zero,
|
||||
don't free the memory */
|
||||
if (ref_count > 0)
|
||||
|
@ -373,9 +370,10 @@ memories_deinstantiate(AOTModuleInstance *module_inst)
|
|||
}
|
||||
|
||||
static AOTMemoryInstance *
|
||||
memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
||||
AOTMemoryInstance *memory_inst, AOTMemory *memory,
|
||||
uint32 heap_size, char *error_buf, uint32 error_buf_size)
|
||||
memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
|
||||
AOTModule *module, AOTMemoryInstance *memory_inst,
|
||||
AOTMemory *memory, uint32 memory_idx, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
void *heap_handle;
|
||||
uint32 num_bytes_per_page = memory->num_bytes_per_page;
|
||||
|
@ -396,23 +394,13 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
|||
bool is_shared_memory = memory->memory_flags & 0x02 ? true : false;
|
||||
|
||||
/* Shared memory */
|
||||
if (is_shared_memory) {
|
||||
if (is_shared_memory && parent != NULL) {
|
||||
AOTMemoryInstance *shared_memory_instance;
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module);
|
||||
/* If the memory of this module has been instantiated,
|
||||
return the memory instance directly */
|
||||
if (node) {
|
||||
uint32 ref_count;
|
||||
ref_count = shared_memory_inc_reference((WASMModuleCommon *)module);
|
||||
bh_assert(ref_count > 0);
|
||||
shared_memory_instance =
|
||||
(AOTMemoryInstance *)shared_memory_get_memory_inst(node);
|
||||
bh_assert(shared_memory_instance);
|
||||
|
||||
(void)ref_count;
|
||||
return shared_memory_instance;
|
||||
}
|
||||
bh_assert(memory_idx == 0);
|
||||
bh_assert(parent->memory_count > memory_idx);
|
||||
shared_memory_instance = parent->memories[memory_idx];
|
||||
shared_memory_inc_reference(shared_memory_instance);
|
||||
return shared_memory_instance;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -609,23 +597,12 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
|||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (is_shared_memory) {
|
||||
memory_inst->is_shared = true;
|
||||
if (!shared_memory_set_memory_inst(
|
||||
(WASMModuleCommon *)module,
|
||||
(WASMMemoryInstanceCommon *)memory_inst)) {
|
||||
set_error_buf(error_buf, error_buf_size, "allocate memory failed");
|
||||
goto fail3;
|
||||
}
|
||||
memory_inst->ref_count = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return memory_inst;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
fail3:
|
||||
if (heap_size > 0)
|
||||
mem_allocator_destroy(memory_inst->heap_handle);
|
||||
#endif
|
||||
fail2:
|
||||
if (heap_size > 0)
|
||||
wasm_runtime_free(memory_inst->heap_handle);
|
||||
|
@ -654,8 +631,9 @@ aot_get_default_memory(AOTModuleInstance *module_inst)
|
|||
}
|
||||
|
||||
static bool
|
||||
memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
||||
uint32 heap_size, char *error_buf, uint32 error_buf_size)
|
||||
memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent,
|
||||
AOTModule *module, uint32 heap_size, char *error_buf,
|
||||
uint32 error_buf_size)
|
||||
{
|
||||
uint32 global_index, global_data_offset, base_offset, length;
|
||||
uint32 i, memory_count = module->memory_count;
|
||||
|
@ -672,8 +650,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
|
|||
|
||||
memories = module_inst->global_table_data.memory_instances;
|
||||
for (i = 0; i < memory_count; i++, memories++) {
|
||||
memory_inst = memory_instantiate(module_inst, module, memories,
|
||||
&module->memories[i], heap_size,
|
||||
memory_inst = memory_instantiate(module_inst, parent, module, memories,
|
||||
&module->memories[i], i, heap_size,
|
||||
error_buf, error_buf_size);
|
||||
if (!memory_inst) {
|
||||
return false;
|
||||
|
@ -1100,9 +1078,9 @@ check_linked_symbol(AOTModule *module, char *error_buf, uint32 error_buf_size)
|
|||
}
|
||||
|
||||
AOTModuleInstance *
|
||||
aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main,
|
||||
uint32 stack_size, uint32 heap_size, char *error_buf,
|
||||
uint32 error_buf_size)
|
||||
aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
|
||||
WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
AOTModuleInstance *module_inst;
|
||||
const uint32 module_inst_struct_size =
|
||||
|
@ -1112,6 +1090,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main,
|
|||
uint64 total_size, table_size = 0;
|
||||
uint8 *p;
|
||||
uint32 i, extra_info_offset;
|
||||
const bool is_sub_inst = parent != NULL;
|
||||
|
||||
/* Check heap size */
|
||||
heap_size = align_uint(heap_size, 8);
|
||||
|
@ -1171,7 +1150,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main,
|
|||
goto fail;
|
||||
|
||||
/* Initialize memory space */
|
||||
if (!memories_instantiate(module_inst, module, heap_size, error_buf,
|
||||
if (!memories_instantiate(module_inst, parent, module, heap_size, error_buf,
|
||||
error_buf_size))
|
||||
goto fail;
|
||||
|
||||
|
@ -1264,16 +1243,6 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
|
|||
wasm_exec_env_destroy((WASMExecEnv *)module_inst->exec_env_singleton);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
/* Destroy wasi resource before freeing app heap, since some fields of
|
||||
wasi contex are allocated from app heap, and if app heap is freed,
|
||||
these fields will be set to NULL, we cannot free their internal data
|
||||
which may allocated from global heap. */
|
||||
/* Only destroy wasi ctx in the main module instance */
|
||||
if (!is_sub_inst)
|
||||
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_PERF_PROFILING != 0
|
||||
if (module_inst->func_perf_profilings)
|
||||
wasm_runtime_free(module_inst->func_perf_profilings);
|
||||
|
@ -1306,10 +1275,14 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
|
|||
wasm_runtime_free(
|
||||
((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports);
|
||||
|
||||
if (!is_sub_inst) {
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
|
||||
#endif
|
||||
#if WASM_ENABLE_WASI_NN != 0
|
||||
if (!is_sub_inst)
|
||||
wasi_nn_destroy(module_inst);
|
||||
#endif
|
||||
}
|
||||
|
||||
wasm_runtime_free(module_inst);
|
||||
}
|
||||
|
@ -2489,13 +2462,13 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx,
|
|||
tbl_seg = module->table_init_data_list[tbl_seg_idx];
|
||||
bh_assert(tbl_seg);
|
||||
|
||||
if (!length) {
|
||||
if (offset_len_out_of_bounds(src_offset, length, tbl_seg->func_index_count)
|
||||
|| offset_len_out_of_bounds(dst_offset, length, tbl_inst->cur_size)) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (length + src_offset > tbl_seg->func_index_count
|
||||
|| dst_offset + length > tbl_inst->cur_size) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
if (!length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2528,8 +2501,9 @@ aot_table_copy(AOTModuleInstance *module_inst, uint32 src_tbl_idx,
|
|||
dst_tbl_inst = module_inst->tables[dst_tbl_idx];
|
||||
bh_assert(dst_tbl_inst);
|
||||
|
||||
if ((uint64)dst_offset + length > dst_tbl_inst->cur_size
|
||||
|| (uint64)src_offset + length > src_tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(dst_offset, length, dst_tbl_inst->cur_size)
|
||||
|| offset_len_out_of_bounds(src_offset, length,
|
||||
src_tbl_inst->cur_size)) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
@ -2554,7 +2528,7 @@ aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 length,
|
|||
tbl_inst = module_inst->tables[tbl_idx];
|
||||
bh_assert(tbl_inst);
|
||||
|
||||
if (data_offset + length > tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(data_offset, length, tbl_inst->cur_size)) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -406,7 +406,7 @@ aot_unload(AOTModule *module);
|
|||
* Instantiate a AOT module.
|
||||
*
|
||||
* @param module the AOT module to instantiate
|
||||
* @param is_sub_inst the flag of sub instance
|
||||
* @param parent the parent module instance
|
||||
* @param heap_size the default heap size of the module instance, a heap will
|
||||
* be created besides the app memory space. Both wasm app and native
|
||||
* function can allocate memory from the heap. If heap_size is 0, the
|
||||
|
@ -417,9 +417,9 @@ aot_unload(AOTModule *module);
|
|||
* @return return the instantiated AOT module instance, NULL if failed
|
||||
*/
|
||||
AOTModuleInstance *
|
||||
aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main,
|
||||
uint32 stack_size, uint32 heap_size, char *error_buf,
|
||||
uint32 error_buf_size);
|
||||
aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
|
||||
WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size);
|
||||
|
||||
/**
|
||||
* Deinstantiate a AOT module instance, destroy the resources.
|
||||
|
|
|
@ -78,6 +78,13 @@ static SymbolMap target_sym_map[] = {
|
|||
REG_SYM(__addsf3),
|
||||
REG_SYM(__divdf3),
|
||||
REG_SYM(__divsf3),
|
||||
REG_SYM(__eqdf2),
|
||||
REG_SYM(__eqsf2),
|
||||
REG_SYM(__extendsfdf2),
|
||||
REG_SYM(__fixunsdfdi),
|
||||
REG_SYM(__fixunsdfsi),
|
||||
REG_SYM(__fixunssfdi),
|
||||
REG_SYM(__fixunssfsi),
|
||||
REG_SYM(__gedf2),
|
||||
REG_SYM(__gesf2),
|
||||
REG_SYM(__gtdf2),
|
||||
|
@ -89,44 +96,33 @@ static SymbolMap target_sym_map[] = {
|
|||
REG_SYM(__muldf3),
|
||||
REG_SYM(__nedf2),
|
||||
REG_SYM(__nesf2),
|
||||
REG_SYM(__eqsf2),
|
||||
REG_SYM(__eqdf2),
|
||||
REG_SYM(__extendsfdf2),
|
||||
REG_SYM(__fixunsdfdi),
|
||||
REG_SYM(__fixunsdfsi),
|
||||
REG_SYM(__fixunssfsi),
|
||||
REG_SYM(__subdf3),
|
||||
REG_SYM(__subsf3),
|
||||
REG_SYM(__truncdfsf2),
|
||||
REG_SYM(__unorddf2),
|
||||
REG_SYM(__unordsf2),
|
||||
#endif
|
||||
REG_SYM(__divdi3),
|
||||
REG_SYM(__divsi3),
|
||||
#if __riscv_xlen == 32
|
||||
REG_SYM(__fixdfdi),
|
||||
REG_SYM(__fixdfsi),
|
||||
REG_SYM(__fixsfdi),
|
||||
REG_SYM(__fixsfsi),
|
||||
#endif
|
||||
REG_SYM(__fixunssfdi),
|
||||
#if __riscv_xlen == 32
|
||||
REG_SYM(__floatdidf),
|
||||
REG_SYM(__floatdisf),
|
||||
REG_SYM(__floatsisf),
|
||||
REG_SYM(__floatsidf),
|
||||
REG_SYM(__floatsisf),
|
||||
REG_SYM(__floatundidf),
|
||||
REG_SYM(__floatundisf),
|
||||
REG_SYM(__floatunsisf),
|
||||
REG_SYM(__floatunsidf),
|
||||
#endif
|
||||
REG_SYM(__moddi3),
|
||||
REG_SYM(__modsi3),
|
||||
REG_SYM(__muldi3),
|
||||
#if __riscv_xlen == 32
|
||||
REG_SYM(__floatunsisf),
|
||||
REG_SYM(__mulsf3),
|
||||
REG_SYM(__mulsi3),
|
||||
#endif
|
||||
#endif
|
||||
REG_SYM(__divdi3),
|
||||
REG_SYM(__divsi3),
|
||||
REG_SYM(__moddi3),
|
||||
REG_SYM(__modsi3),
|
||||
REG_SYM(__muldi3),
|
||||
REG_SYM(__udivdi3),
|
||||
REG_SYM(__udivsi3),
|
||||
REG_SYM(__umoddi3),
|
||||
|
|
|
@ -43,6 +43,11 @@ void __floatdidf();
|
|||
void __divsf3();
|
||||
void __fixdfdi();
|
||||
void __floatundidf();
|
||||
void __fixsfdi();
|
||||
void __fixunssfdi();
|
||||
void __fixunsdfdi();
|
||||
void __floatdisf();
|
||||
void __floatundisf();
|
||||
|
||||
|
||||
static SymbolMap target_sym_map[] = {
|
||||
|
@ -85,6 +90,11 @@ static SymbolMap target_sym_map[] = {
|
|||
REG_SYM(__divsf3),
|
||||
REG_SYM(__fixdfdi),
|
||||
REG_SYM(__floatundidf),
|
||||
REG_SYM(__fixsfdi),
|
||||
REG_SYM(__fixunssfdi),
|
||||
REG_SYM(__fixunsdfdi),
|
||||
REG_SYM(__floatdisf),
|
||||
REG_SYM(__floatundisf),
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
|
@ -207,6 +217,10 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
|
|||
case R_XTENSA_32:
|
||||
{
|
||||
uint8 *insn_addr = target_section_addr + reloc_offset;
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
insn_addr = os_get_dbus_mirror((void *)insn_addr);
|
||||
bh_assert(insn_addr != NULL);
|
||||
#endif
|
||||
int32 initial_addend;
|
||||
/* (S + A) */
|
||||
if ((intptr_t)insn_addr & 3) {
|
||||
|
@ -265,6 +279,11 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
insn_addr = os_get_dbus_mirror((void *)insn_addr);
|
||||
bh_assert(insn_addr != NULL);
|
||||
l32r_insn = (l32r_insn_t *)insn_addr;
|
||||
#endif
|
||||
imm16 = (int16)(relative_offset >> 2);
|
||||
|
||||
/* write back the imm16 to the l32r instruction */
|
||||
|
@ -285,7 +304,6 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
|
|||
#if __GNUC__ >= 9
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define _WASM_EXEC_ENV_H
|
||||
|
||||
#include "bh_assert.h"
|
||||
#include "wasm_suspend_flags.h"
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
#include "../interpreter/wasm.h"
|
||||
#endif
|
||||
|
@ -57,15 +58,8 @@ typedef struct WASMExecEnv {
|
|||
exception. */
|
||||
uint8 *native_stack_boundary;
|
||||
|
||||
/* Used to terminate or suspend current thread
|
||||
bit 0: need to terminate
|
||||
bit 1: need to suspend
|
||||
bit 2: need to go into breakpoint
|
||||
bit 3: return from pthread_exit */
|
||||
union {
|
||||
uint32 flags;
|
||||
uintptr_t __padding__;
|
||||
} suspend_flags;
|
||||
/* Used to terminate or suspend current thread */
|
||||
WASMSuspendFlags suspend_flags;
|
||||
|
||||
/* Auxiliary stack boundary */
|
||||
union {
|
||||
|
|
|
@ -608,7 +608,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
|
|||
}
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (memory->is_shared) {
|
||||
if (shared_memory_is_shared(memory)) {
|
||||
memory->num_bytes_per_page = num_bytes_per_page;
|
||||
memory->cur_page_count = total_page_count;
|
||||
memory->max_page_count = max_page_count;
|
||||
|
@ -769,52 +769,14 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
|
|||
bool ret = false;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
|
||||
if (node)
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
if (module->memory_count > 0)
|
||||
shared_memory_lock(module->memories[0]);
|
||||
#endif
|
||||
ret = wasm_enlarge_memory_internal(module, inc_page_count);
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (node)
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
if (module->memory_count > 0)
|
||||
shared_memory_unlock(module->memories[0]);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|
||||
|| WASM_ENABLE_BULK_MEMORY != 0
|
||||
uint32
|
||||
wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node)
|
||||
{
|
||||
uint32 num_bytes_per_page;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (node)
|
||||
os_mutex_lock(&((WASMSharedMemNode *)node)->shared_mem_lock);
|
||||
#endif
|
||||
num_bytes_per_page = memory->num_bytes_per_page;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (node)
|
||||
os_mutex_unlock(&((WASMSharedMemNode *)node)->shared_mem_lock);
|
||||
#endif
|
||||
return num_bytes_per_page;
|
||||
}
|
||||
|
||||
uint32
|
||||
wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node)
|
||||
{
|
||||
uint32 linear_mem_size;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (node)
|
||||
os_mutex_lock(&((WASMSharedMemNode *)node)->shared_mem_lock);
|
||||
#endif
|
||||
linear_mem_size = memory->num_bytes_per_page * memory->cur_page_count;
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (node)
|
||||
os_mutex_unlock(&((WASMSharedMemNode *)node)->shared_mem_lock);
|
||||
#endif
|
||||
return linear_mem_size;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -24,16 +24,6 @@ wasm_runtime_memory_destroy();
|
|||
unsigned
|
||||
wasm_runtime_memory_pool_size();
|
||||
|
||||
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|
||||
|| WASM_ENABLE_BULK_MEMORY != 0
|
||||
uint32
|
||||
wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node);
|
||||
|
||||
uint32
|
||||
wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1196,7 +1196,8 @@ wasm_runtime_unload(WASMModuleCommon *module)
|
|||
}
|
||||
|
||||
WASMModuleInstanceCommon *
|
||||
wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst,
|
||||
wasm_runtime_instantiate_internal(WASMModuleCommon *module,
|
||||
WASMModuleInstanceCommon *parent,
|
||||
WASMExecEnv *exec_env_main, uint32 stack_size,
|
||||
uint32 heap_size, char *error_buf,
|
||||
uint32 error_buf_size)
|
||||
|
@ -1204,14 +1205,14 @@ wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst,
|
|||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module->module_type == Wasm_Module_Bytecode)
|
||||
return (WASMModuleInstanceCommon *)wasm_instantiate(
|
||||
(WASMModule *)module, is_sub_inst, exec_env_main, stack_size,
|
||||
heap_size, error_buf, error_buf_size);
|
||||
(WASMModule *)module, (WASMModuleInstance *)parent, exec_env_main,
|
||||
stack_size, heap_size, error_buf, error_buf_size);
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module->module_type == Wasm_Module_AoT)
|
||||
return (WASMModuleInstanceCommon *)aot_instantiate(
|
||||
(AOTModule *)module, is_sub_inst, exec_env_main, stack_size,
|
||||
heap_size, error_buf, error_buf_size);
|
||||
(AOTModule *)module, (AOTModuleInstance *)parent, exec_env_main,
|
||||
stack_size, heap_size, error_buf, error_buf_size);
|
||||
#endif
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Instantiate module failed, invalid module type");
|
||||
|
@ -1224,7 +1225,7 @@ wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size,
|
|||
uint32 error_buf_size)
|
||||
{
|
||||
return wasm_runtime_instantiate_internal(
|
||||
module, false, NULL, stack_size, heap_size, error_buf, error_buf_size);
|
||||
module, NULL, NULL, stack_size, heap_size, error_buf, error_buf_size);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2310,10 +2311,8 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
|
|||
WASMExecEnv *exec_env = NULL;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module_inst->module);
|
||||
if (node)
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
if (module_inst->memory_count > 0)
|
||||
shared_memory_lock(module_inst->memories[0]);
|
||||
#endif
|
||||
if (exception) {
|
||||
snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception),
|
||||
|
@ -2323,8 +2322,8 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *exception)
|
|||
module_inst->cur_exception[0] = '\0';
|
||||
}
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (node)
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
if (module_inst->memory_count > 0)
|
||||
shared_memory_unlock(module_inst->memories[0]);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
|
@ -2386,10 +2385,8 @@ wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf)
|
|||
bool has_exception = false;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module_inst->module);
|
||||
if (node)
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
if (module_inst->memory_count > 0)
|
||||
shared_memory_lock(module_inst->memories[0]);
|
||||
#endif
|
||||
if (module_inst->cur_exception[0] != '\0') {
|
||||
/* NULL is passed if the caller is not interested in getting the
|
||||
|
@ -2403,8 +2400,8 @@ wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf)
|
|||
has_exception = true;
|
||||
}
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (node)
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
if (module_inst->memory_count > 0)
|
||||
shared_memory_unlock(module_inst->memories[0]);
|
||||
#endif
|
||||
|
||||
return has_exception;
|
||||
|
|
|
@ -498,7 +498,8 @@ wasm_runtime_unload(WASMModuleCommon *module);
|
|||
|
||||
/* Internal API */
|
||||
WASMModuleInstanceCommon *
|
||||
wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst,
|
||||
wasm_runtime_instantiate_internal(WASMModuleCommon *module,
|
||||
WASMModuleInstanceCommon *parent,
|
||||
WASMExecEnv *exec_env_main, uint32 stack_size,
|
||||
uint32 heap_size, char *error_buf,
|
||||
uint32 error_buf_size);
|
||||
|
|
|
@ -9,9 +9,16 @@
|
|||
#include "../libraries/thread-mgr/thread_manager.h"
|
||||
#endif
|
||||
|
||||
static bh_list shared_memory_list_head;
|
||||
static bh_list *const shared_memory_list = &shared_memory_list_head;
|
||||
static korp_mutex shared_memory_list_lock;
|
||||
/*
|
||||
* Note: this lock can be per memory.
|
||||
*
|
||||
* For now, just use a global because:
|
||||
* - it's a bit cumbersome to extend WASMMemoryInstance w/o breaking
|
||||
* the AOT ABI.
|
||||
* - If you care performance, it's better to make the interpreters
|
||||
* use atomic ops.
|
||||
*/
|
||||
static korp_mutex _shared_memory_lock;
|
||||
|
||||
/* clang-format off */
|
||||
enum {
|
||||
|
@ -48,17 +55,15 @@ destroy_wait_info(void *wait_info);
|
|||
bool
|
||||
wasm_shared_memory_init()
|
||||
{
|
||||
if (os_mutex_init(&shared_memory_list_lock) != 0)
|
||||
if (os_mutex_init(&_shared_memory_lock) != 0)
|
||||
return false;
|
||||
|
||||
/* wait map not exists, create new map */
|
||||
if (!(wait_map = bh_hash_map_create(32, true, (HashFunc)wait_address_hash,
|
||||
(KeyEqualFunc)wait_address_equal, NULL,
|
||||
destroy_wait_info))) {
|
||||
os_mutex_destroy(&shared_memory_list_lock);
|
||||
os_mutex_destroy(&_shared_memory_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -66,110 +71,79 @@ void
|
|||
wasm_shared_memory_destroy()
|
||||
{
|
||||
bh_hash_map_destroy(wait_map);
|
||||
os_mutex_destroy(&shared_memory_list_lock);
|
||||
os_mutex_destroy(&_shared_memory_lock);
|
||||
}
|
||||
|
||||
static WASMSharedMemNode *
|
||||
search_module(WASMModuleCommon *module)
|
||||
uint32
|
||||
shared_memory_inc_reference(WASMMemoryInstance *memory)
|
||||
{
|
||||
WASMSharedMemNode *node;
|
||||
|
||||
os_mutex_lock(&shared_memory_list_lock);
|
||||
node = bh_list_first_elem(shared_memory_list);
|
||||
|
||||
while (node) {
|
||||
if (module == node->module) {
|
||||
os_mutex_unlock(&shared_memory_list_lock);
|
||||
return node;
|
||||
}
|
||||
node = bh_list_elem_next(node);
|
||||
}
|
||||
|
||||
os_mutex_unlock(&shared_memory_list_lock);
|
||||
return NULL;
|
||||
bh_assert(shared_memory_is_shared(memory));
|
||||
uint32 old;
|
||||
#if BH_ATOMIC_32_IS_ATOMIC == 0
|
||||
os_mutex_lock(&_shared_memory_lock);
|
||||
#endif
|
||||
old = BH_ATOMIC_32_FETCH_ADD(memory->ref_count, 1);
|
||||
#if BH_ATOMIC_32_IS_ATOMIC == 0
|
||||
os_mutex_unlock(&_shared_memory_lock);
|
||||
#endif
|
||||
bh_assert(old >= 1);
|
||||
bh_assert(old < UINT32_MAX);
|
||||
return old + 1;
|
||||
}
|
||||
|
||||
WASMSharedMemNode *
|
||||
wasm_module_get_shared_memory(WASMModuleCommon *module)
|
||||
uint32
|
||||
shared_memory_dec_reference(WASMMemoryInstance *memory)
|
||||
{
|
||||
return search_module(module);
|
||||
bh_assert(shared_memory_is_shared(memory));
|
||||
uint32 old;
|
||||
#if BH_ATOMIC_32_IS_ATOMIC == 0
|
||||
os_mutex_lock(&_shared_memory_lock);
|
||||
#endif
|
||||
old = BH_ATOMIC_32_FETCH_SUB(memory->ref_count, 1);
|
||||
#if BH_ATOMIC_32_IS_ATOMIC == 0
|
||||
os_mutex_unlock(&_shared_memory_lock);
|
||||
#endif
|
||||
bh_assert(old > 0);
|
||||
return old - 1;
|
||||
}
|
||||
|
||||
int32
|
||||
shared_memory_inc_reference(WASMModuleCommon *module)
|
||||
bool
|
||||
shared_memory_is_shared(WASMMemoryInstance *memory)
|
||||
{
|
||||
WASMSharedMemNode *node = search_module(module);
|
||||
uint32 ref_count = -1;
|
||||
if (node) {
|
||||
os_mutex_lock(&node->lock);
|
||||
ref_count = ++node->ref_count;
|
||||
os_mutex_unlock(&node->lock);
|
||||
}
|
||||
return ref_count;
|
||||
uint32 old;
|
||||
#if BH_ATOMIC_32_IS_ATOMIC == 0
|
||||
os_mutex_lock(&_shared_memory_lock);
|
||||
#endif
|
||||
old = BH_ATOMIC_32_LOAD(memory->ref_count);
|
||||
#if BH_ATOMIC_32_IS_ATOMIC == 0
|
||||
os_mutex_unlock(&_shared_memory_lock);
|
||||
#endif
|
||||
return old > 0;
|
||||
}
|
||||
|
||||
int32
|
||||
shared_memory_dec_reference(WASMModuleCommon *module)
|
||||
static korp_mutex *
|
||||
shared_memory_get_lock_pointer(WASMMemoryInstance *memory)
|
||||
{
|
||||
WASMSharedMemNode *node = search_module(module);
|
||||
uint32 ref_count = 0;
|
||||
if (node) {
|
||||
os_mutex_lock(&node->lock);
|
||||
ref_count = --node->ref_count;
|
||||
os_mutex_unlock(&node->lock);
|
||||
if (ref_count == 0) {
|
||||
os_mutex_lock(&shared_memory_list_lock);
|
||||
bh_list_remove(shared_memory_list, node);
|
||||
os_mutex_unlock(&shared_memory_list_lock);
|
||||
|
||||
os_mutex_destroy(&node->shared_mem_lock);
|
||||
os_mutex_destroy(&node->lock);
|
||||
wasm_runtime_free(node);
|
||||
}
|
||||
return ref_count;
|
||||
}
|
||||
|
||||
return -1;
|
||||
bh_assert(memory != NULL);
|
||||
return &_shared_memory_lock;
|
||||
}
|
||||
|
||||
WASMMemoryInstanceCommon *
|
||||
shared_memory_get_memory_inst(WASMSharedMemNode *node)
|
||||
void
|
||||
shared_memory_lock(WASMMemoryInstance *memory)
|
||||
{
|
||||
return node->memory_inst;
|
||||
/*
|
||||
* Note: exception logic is currently abusing this lock.
|
||||
* cf. https://github.com/bytecodealliance/wasm-micro-runtime/issues/2407
|
||||
*/
|
||||
bh_assert(memory != NULL);
|
||||
os_mutex_lock(&_shared_memory_lock);
|
||||
}
|
||||
|
||||
WASMSharedMemNode *
|
||||
shared_memory_set_memory_inst(WASMModuleCommon *module,
|
||||
WASMMemoryInstanceCommon *memory)
|
||||
void
|
||||
shared_memory_unlock(WASMMemoryInstance *memory)
|
||||
{
|
||||
WASMSharedMemNode *node;
|
||||
bh_list_status ret;
|
||||
|
||||
if (!(node = wasm_runtime_malloc(sizeof(WASMSharedMemNode))))
|
||||
return NULL;
|
||||
|
||||
node->module = module;
|
||||
node->memory_inst = memory;
|
||||
node->ref_count = 1;
|
||||
|
||||
if (os_mutex_init(&node->shared_mem_lock) != 0) {
|
||||
wasm_runtime_free(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (os_mutex_init(&node->lock) != 0) {
|
||||
os_mutex_destroy(&node->shared_mem_lock);
|
||||
wasm_runtime_free(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_mutex_lock(&shared_memory_list_lock);
|
||||
ret = bh_list_insert(shared_memory_list, node);
|
||||
bh_assert(ret == BH_LIST_SUCCESS);
|
||||
os_mutex_unlock(&shared_memory_list_lock);
|
||||
|
||||
(void)ret;
|
||||
return node;
|
||||
bh_assert(memory != NULL);
|
||||
os_mutex_unlock(&_shared_memory_lock);
|
||||
}
|
||||
|
||||
/* Atomics wait && notify APIs */
|
||||
|
@ -307,7 +281,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|||
WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
|
||||
AtomicWaitInfo *wait_info;
|
||||
AtomicWaitNode *wait_node;
|
||||
WASMSharedMemNode *node;
|
||||
korp_mutex *lock;
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
WASMExecEnv *exec_env;
|
||||
#endif
|
||||
|
@ -322,7 +296,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|||
}
|
||||
|
||||
/* Currently we have only one memory instance */
|
||||
if (!module_inst->memories[0]->is_shared) {
|
||||
if (!shared_memory_is_shared(module_inst->memories[0])) {
|
||||
wasm_runtime_set_exception(module, "expected shared memory");
|
||||
return -1;
|
||||
}
|
||||
|
@ -340,30 +314,29 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|||
bh_assert(exec_env);
|
||||
#endif
|
||||
|
||||
node = search_module((WASMModuleCommon *)module_inst->module);
|
||||
bh_assert(node);
|
||||
lock = shared_memory_get_lock_pointer(module_inst->memories[0]);
|
||||
|
||||
/* Lock the shared_mem_lock for the whole atomic wait process,
|
||||
and use it to os_cond_reltimedwait */
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
os_mutex_lock(lock);
|
||||
|
||||
no_wait = (!wait64 && *(uint32 *)address != (uint32)expect)
|
||||
|| (wait64 && *(uint64 *)address != expect);
|
||||
|
||||
if (no_wait) {
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
os_mutex_unlock(lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) {
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
os_mutex_unlock(lock);
|
||||
wasm_runtime_set_exception(module, "failed to create wait node");
|
||||
return -1;
|
||||
}
|
||||
memset(wait_node, 0, sizeof(AtomicWaitNode));
|
||||
|
||||
if (0 != os_cond_init(&wait_node->wait_cond)) {
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
os_mutex_unlock(lock);
|
||||
wasm_runtime_free(wait_node);
|
||||
wasm_runtime_set_exception(module, "failed to init wait cond");
|
||||
return -1;
|
||||
|
@ -375,7 +348,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|||
wait_info = acquire_wait_info(address, wait_node);
|
||||
|
||||
if (!wait_info) {
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
os_mutex_unlock(lock);
|
||||
os_cond_destroy(&wait_node->wait_cond);
|
||||
wasm_runtime_free(wait_node);
|
||||
wasm_runtime_set_exception(module, "failed to acquire wait_info");
|
||||
|
@ -390,7 +363,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|||
if (timeout < 0) {
|
||||
/* wait forever until it is notified or terminatied
|
||||
here we keep waiting and checking every second */
|
||||
os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_lock,
|
||||
os_cond_reltimedwait(&wait_node->wait_cond, lock,
|
||||
(uint64)timeout_1sec);
|
||||
if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
|
@ -404,8 +377,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|||
else {
|
||||
timeout_wait =
|
||||
timeout_left < timeout_1sec ? timeout_left : timeout_1sec;
|
||||
os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_lock,
|
||||
timeout_wait);
|
||||
os_cond_reltimedwait(&wait_node->wait_cond, lock, timeout_wait);
|
||||
if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */
|
||||
|| timeout_left <= timeout_wait /* time out */
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
|
@ -433,7 +405,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|||
/* Release wait info if no wait nodes are attached */
|
||||
map_try_release_wait_info(wait_map, wait_info, address);
|
||||
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
os_mutex_unlock(lock);
|
||||
|
||||
return is_timeout ? 2 : 0;
|
||||
}
|
||||
|
@ -445,7 +417,7 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
|
|||
WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
|
||||
uint32 notify_result;
|
||||
AtomicWaitInfo *wait_info;
|
||||
WASMSharedMemNode *node;
|
||||
korp_mutex *lock;
|
||||
bool out_of_bounds;
|
||||
|
||||
bh_assert(module->module_type == Wasm_Module_Bytecode
|
||||
|
@ -461,31 +433,30 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
|
|||
}
|
||||
|
||||
/* Currently we have only one memory instance */
|
||||
if (!module_inst->memories[0]->is_shared) {
|
||||
if (!shared_memory_is_shared(module_inst->memories[0])) {
|
||||
/* Always return 0 for ushared linear memory since there is
|
||||
no way to create a waiter on it */
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = search_module((WASMModuleCommon *)module_inst->module);
|
||||
bh_assert(node);
|
||||
lock = shared_memory_get_lock_pointer(module_inst->memories[0]);
|
||||
|
||||
/* Lock the shared_mem_lock for the whole atomic notify process,
|
||||
and use it to os_cond_signal */
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
os_mutex_lock(lock);
|
||||
|
||||
wait_info = acquire_wait_info(address, NULL);
|
||||
|
||||
/* Nobody wait on this address */
|
||||
if (!wait_info) {
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
os_mutex_unlock(lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Notify each wait node in the wait list */
|
||||
notify_result = notify_wait_list(wait_info->wait_list, count);
|
||||
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
os_mutex_unlock(lock);
|
||||
|
||||
return notify_result;
|
||||
}
|
||||
|
|
|
@ -7,53 +7,33 @@
|
|||
#define _WASM_SHARED_MEMORY_H
|
||||
|
||||
#include "bh_common.h"
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
#include "wasm_runtime.h"
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
#include "aot_runtime.h"
|
||||
#endif
|
||||
#include "../interpreter/wasm_runtime.h"
|
||||
#include "wasm_runtime_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct WASMSharedMemNode {
|
||||
bh_list_link l;
|
||||
/* Lock */
|
||||
korp_mutex lock;
|
||||
/* The module reference */
|
||||
WASMModuleCommon *module;
|
||||
/* The memory information */
|
||||
WASMMemoryInstanceCommon *memory_inst;
|
||||
/* Lock used for atomic operations */
|
||||
korp_mutex shared_mem_lock;
|
||||
|
||||
/* reference count */
|
||||
uint32 ref_count;
|
||||
} WASMSharedMemNode;
|
||||
|
||||
bool
|
||||
wasm_shared_memory_init();
|
||||
|
||||
void
|
||||
wasm_shared_memory_destroy();
|
||||
|
||||
WASMSharedMemNode *
|
||||
wasm_module_get_shared_memory(WASMModuleCommon *module);
|
||||
uint32
|
||||
shared_memory_inc_reference(WASMMemoryInstance *memory);
|
||||
|
||||
int32
|
||||
shared_memory_inc_reference(WASMModuleCommon *module);
|
||||
uint32
|
||||
shared_memory_dec_reference(WASMMemoryInstance *memory);
|
||||
|
||||
int32
|
||||
shared_memory_dec_reference(WASMModuleCommon *module);
|
||||
bool
|
||||
shared_memory_is_shared(WASMMemoryInstance *memory);
|
||||
|
||||
WASMMemoryInstanceCommon *
|
||||
shared_memory_get_memory_inst(WASMSharedMemNode *node);
|
||||
void
|
||||
shared_memory_lock(WASMMemoryInstance *memory);
|
||||
|
||||
WASMSharedMemNode *
|
||||
shared_memory_set_memory_inst(WASMModuleCommon *module,
|
||||
WASMMemoryInstanceCommon *memory);
|
||||
void
|
||||
shared_memory_unlock(WASMMemoryInstance *memory);
|
||||
|
||||
uint32
|
||||
wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
||||
|
|
48
core/iwasm/common/wasm_suspend_flags.h
Normal file
48
core/iwasm/common/wasm_suspend_flags.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Amazon Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _WASM_SUSPEND_FLAGS_H
|
||||
#define _WASM_SUSPEND_FLAGS_H
|
||||
|
||||
#include "bh_atomic.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Need to terminate */
|
||||
#define WASM_SUSPEND_FLAG_TERMINATE 0x1
|
||||
/* Need to suspend */
|
||||
#define WASM_SUSPEND_FLAG_SUSPEND 0x2
|
||||
/* Need to go into breakpoint */
|
||||
#define WASM_SUSPEND_FLAG_BREAKPOINT 0x4
|
||||
/* Return from pthread_exit */
|
||||
#define WASM_SUSPEND_FLAG_EXIT 0x8
|
||||
|
||||
typedef union WASMSuspendFlags {
|
||||
bh_atomic_32_t flags;
|
||||
uintptr_t __padding__;
|
||||
} WASMSuspendFlags;
|
||||
|
||||
#define WASM_SUSPEND_FLAGS_IS_ATOMIC BH_ATOMIC_32_IS_ATOMIC
|
||||
#define WASM_SUSPEND_FLAGS_GET(s_flags) BH_ATOMIC_32_LOAD(s_flags.flags)
|
||||
#define WASM_SUSPEND_FLAGS_FETCH_OR(s_flags, val) \
|
||||
BH_ATOMIC_32_FETCH_OR(s_flags.flags, val)
|
||||
#define WASM_SUSPEND_FLAGS_FETCH_AND(s_flags, val) \
|
||||
BH_ATOMIC_32_FETCH_AND(s_flags.flags, val)
|
||||
|
||||
#if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0
|
||||
#define WASM_SUSPEND_FLAGS_LOCK(lock) (void)0
|
||||
#define WASM_SUSPEND_FLAGS_UNLOCK(lock) (void)0
|
||||
#else /* else of WASM_SUSPEND_FLAGS_IS_ATOMIC */
|
||||
#define WASM_SUSPEND_FLAGS_LOCK(lock) os_mutex_lock(&lock)
|
||||
#define WASM_SUSPEND_FLAGS_UNLOCK(lock) os_mutex_unlock(&lock);
|
||||
#endif /* WASM_SUSPEND_FLAGS_IS_ATOMIC */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* end of _WASM_SUSPEND_FLAGS_H */
|
|
@ -43,7 +43,7 @@ typedef WASMType AOTFuncType;
|
|||
typedef WASMExport AOTExport;
|
||||
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
typedef void *dwar_extractor_handle_t;
|
||||
typedef void *dwarf_extractor_handle_t;
|
||||
#endif
|
||||
|
||||
typedef enum AOTIntCond {
|
||||
|
@ -285,7 +285,7 @@ typedef struct AOTCompData {
|
|||
|
||||
WASMModule *wasm_module;
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
dwar_extractor_handle_t extractor;
|
||||
dwarf_extractor_handle_t extractor;
|
||||
#endif
|
||||
} AOTCompData;
|
||||
|
||||
|
|
|
@ -2696,7 +2696,7 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
|
|||
if (comp_ctx->stack_sizes != NULL) {
|
||||
LLVMOrcJITTargetAddress addr;
|
||||
if ((err = LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &addr,
|
||||
aot_stack_sizes_name))) {
|
||||
aot_stack_sizes_alias_name))) {
|
||||
aot_handle_llvm_errmsg("failed to look up stack_sizes", err);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -82,43 +82,40 @@ class ExpandMemoryOpPass : public PassInfoMixin<ExpandMemoryOpPass>
|
|||
PreservedAnalyses
|
||||
ExpandMemoryOpPass::run(Function &F, FunctionAnalysisManager &AM)
|
||||
{
|
||||
Intrinsic::ID ID = F.getIntrinsicID();
|
||||
bool Changed = false;
|
||||
SmallVector<MemIntrinsic *, 16> MemCalls;
|
||||
|
||||
for (auto I = F.user_begin(), E = F.user_end(); I != E;) {
|
||||
Instruction *Inst = cast<Instruction>(*I);
|
||||
++I;
|
||||
/* Iterate over all instructions in the function, looking for memcpy,
|
||||
* memmove, and memset. When we find one, expand it into a loop. */
|
||||
|
||||
switch (ID) {
|
||||
case Intrinsic::memcpy:
|
||||
{
|
||||
auto *Memcpy = cast<MemCpyInst>(Inst);
|
||||
Function *ParentFunc = Memcpy->getParent()->getParent();
|
||||
const TargetTransformInfo &TTI =
|
||||
AM.getResult<TargetIRAnalysis>(*ParentFunc);
|
||||
expandMemCpyAsLoop(Memcpy, TTI);
|
||||
Memcpy->eraseFromParent();
|
||||
Changed = true;
|
||||
break;
|
||||
for (auto &BB : F) {
|
||||
for (auto &Inst : BB) {
|
||||
if (auto *Memcpy = dyn_cast_or_null<MemCpyInst>(&Inst)) {
|
||||
MemCalls.push_back(Memcpy);
|
||||
}
|
||||
case Intrinsic::memmove:
|
||||
{
|
||||
auto *Memmove = cast<MemMoveInst>(Inst);
|
||||
expandMemMoveAsLoop(Memmove);
|
||||
Memmove->eraseFromParent();
|
||||
Changed = true;
|
||||
break;
|
||||
else if (auto *Memmove = dyn_cast_or_null<MemMoveInst>(&Inst)) {
|
||||
MemCalls.push_back(Memmove);
|
||||
}
|
||||
case Intrinsic::memset:
|
||||
{
|
||||
auto *Memset = cast<MemSetInst>(Inst);
|
||||
expandMemSetAsLoop(Memset);
|
||||
Memset->eraseFromParent();
|
||||
Changed = true;
|
||||
break;
|
||||
else if (auto *Memset = dyn_cast_or_null<MemSetInst>(&Inst)) {
|
||||
MemCalls.push_back(Memset);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (MemIntrinsic *MemCall : MemCalls) {
|
||||
if (MemCpyInst *Memcpy = dyn_cast<MemCpyInst>(MemCall)) {
|
||||
Function *ParentFunc = Memcpy->getParent()->getParent();
|
||||
const TargetTransformInfo &TTI =
|
||||
AM.getResult<TargetIRAnalysis>(*ParentFunc);
|
||||
expandMemCpyAsLoop(Memcpy, TTI);
|
||||
Memcpy->eraseFromParent();
|
||||
}
|
||||
else if (MemMoveInst *Memmove = dyn_cast<MemMoveInst>(MemCall)) {
|
||||
expandMemMoveAsLoop(Memmove);
|
||||
Memmove->eraseFromParent();
|
||||
}
|
||||
else if (MemSetInst *Memset = dyn_cast<MemSetInst>(MemCall)) {
|
||||
expandMemSetAsLoop(Memset);
|
||||
Memset->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,13 +294,6 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
|
|||
FPM.addPass(SLPVectorizerPass());
|
||||
FPM.addPass(LoadStoreVectorizerPass());
|
||||
|
||||
/* Run specific passes for AOT indirect mode in last since general
|
||||
optimization may create some intrinsic function calls like
|
||||
llvm.memset, so let's remove these function calls here. */
|
||||
if (comp_ctx->is_indirect_mode) {
|
||||
FPM.addPass(ExpandMemoryOpPass());
|
||||
}
|
||||
|
||||
if (comp_ctx->enable_llvm_pgo || comp_ctx->use_prof_file) {
|
||||
/* LICM pass: loop invariant code motion, attempting to remove
|
||||
as much code from the body of a loop as possible. Experiments
|
||||
|
@ -341,6 +331,15 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
|
|||
else {
|
||||
MPM.addPass(PB.buildPerModuleDefaultPipeline(OL));
|
||||
}
|
||||
|
||||
/* Run specific passes for AOT indirect mode in last since general
|
||||
optimization may create some intrinsic function calls like
|
||||
llvm.memset, so let's remove these function calls here. */
|
||||
if (comp_ctx->is_indirect_mode) {
|
||||
FunctionPassManager FPM1;
|
||||
FPM1.addPass(ExpandMemoryOpPass());
|
||||
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM1)));
|
||||
}
|
||||
}
|
||||
|
||||
MPM.run(*M, MAM);
|
||||
|
|
|
@ -28,25 +28,25 @@
|
|||
|
||||
using namespace lldb;
|
||||
|
||||
typedef struct dwar_extractor {
|
||||
typedef struct dwarf_extractor {
|
||||
SBDebugger debugger;
|
||||
SBTarget target;
|
||||
SBModule module;
|
||||
|
||||
} dwar_extractor;
|
||||
} dwarf_extractor;
|
||||
|
||||
#define TO_HANDLE(extractor) (dwar_extractor_handle_t)(extractor)
|
||||
#define TO_HANDLE(extractor) (dwarf_extractor_handle_t)(extractor)
|
||||
|
||||
#define TO_EXTACTOR(handle) (dwar_extractor *)(handle)
|
||||
#define TO_EXTACTOR(handle) (dwarf_extractor *)(handle)
|
||||
|
||||
static bool is_debugger_initialized;
|
||||
|
||||
dwar_extractor_handle_t
|
||||
dwarf_extractor_handle_t
|
||||
create_dwarf_extractor(AOTCompData *comp_data, char *file_name)
|
||||
{
|
||||
char *arch = NULL;
|
||||
char *platform = NULL;
|
||||
dwar_extractor *extractor = NULL;
|
||||
dwarf_extractor *extractor = NULL;
|
||||
|
||||
//__attribute__((constructor)) may be better?
|
||||
if (!is_debugger_initialized) {
|
||||
|
@ -61,7 +61,7 @@ create_dwarf_extractor(AOTCompData *comp_data, char *file_name)
|
|||
SBError error;
|
||||
SBFileSpec exe_file_spec(file_name, true);
|
||||
|
||||
if (!(extractor = new dwar_extractor())) {
|
||||
if (!(extractor = new dwarf_extractor())) {
|
||||
LOG_ERROR("Create Dwarf Extractor error: failed to allocate memory");
|
||||
goto fail3;
|
||||
}
|
||||
|
@ -101,9 +101,9 @@ fail3:
|
|||
}
|
||||
|
||||
void
|
||||
destroy_dwarf_extractor(dwar_extractor_handle_t handle)
|
||||
destroy_dwarf_extractor(dwarf_extractor_handle_t handle)
|
||||
{
|
||||
dwar_extractor *extractor = TO_EXTACTOR(handle);
|
||||
dwarf_extractor *extractor = TO_EXTACTOR(handle);
|
||||
if (!extractor)
|
||||
return;
|
||||
extractor->debugger.DeleteTarget(extractor->target);
|
||||
|
@ -116,7 +116,7 @@ destroy_dwarf_extractor(dwar_extractor_handle_t handle)
|
|||
LLVMMetadataRef
|
||||
dwarf_gen_file_info(const AOTCompContext *comp_ctx)
|
||||
{
|
||||
dwar_extractor *extractor;
|
||||
dwarf_extractor *extractor;
|
||||
int units_number;
|
||||
LLVMMetadataRef file_info = NULL;
|
||||
const char *file_name;
|
||||
|
@ -193,7 +193,7 @@ dwarf_gen_mock_vm_info(AOTCompContext *comp_ctx)
|
|||
LLVMMetadataRef
|
||||
dwarf_gen_comp_unit_info(const AOTCompContext *comp_ctx)
|
||||
{
|
||||
dwar_extractor *extractor;
|
||||
dwarf_extractor *extractor;
|
||||
int units_number;
|
||||
LLVMMetadataRef comp_unit = NULL;
|
||||
|
||||
|
@ -292,7 +292,7 @@ lldb_function_to_function_dbi(const AOTCompContext *comp_ctx,
|
|||
SBTypeList function_args = function.GetType().GetFunctionArgumentTypes();
|
||||
SBType return_type = function.GetType().GetFunctionReturnType();
|
||||
const size_t num_function_args = function_args.GetSize();
|
||||
dwar_extractor *extractor;
|
||||
dwarf_extractor *extractor;
|
||||
|
||||
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
|
||||
return NULL;
|
||||
|
@ -393,7 +393,7 @@ dwarf_gen_func_info(const AOTCompContext *comp_ctx,
|
|||
const AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMMetadataRef func_info = NULL;
|
||||
dwar_extractor *extractor;
|
||||
dwarf_extractor *extractor;
|
||||
uint64_t vm_offset;
|
||||
AOTFunc *func = func_ctx->aot_func;
|
||||
|
||||
|
@ -423,7 +423,7 @@ dwarf_get_func_name(const AOTCompContext *comp_ctx,
|
|||
const AOTFuncContext *func_ctx, char *name, int len)
|
||||
{
|
||||
LLVMMetadataRef func_info = NULL;
|
||||
dwar_extractor *extractor;
|
||||
dwarf_extractor *extractor;
|
||||
uint64_t vm_offset;
|
||||
AOTFunc *func = func_ctx->aot_func;
|
||||
|
||||
|
@ -454,7 +454,7 @@ dwarf_gen_location(const AOTCompContext *comp_ctx,
|
|||
const AOTFuncContext *func_ctx, uint64_t vm_offset)
|
||||
{
|
||||
LLVMMetadataRef location_info = NULL;
|
||||
dwar_extractor *extractor;
|
||||
dwarf_extractor *extractor;
|
||||
AOTFunc *func = func_ctx->aot_func;
|
||||
|
||||
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
|
||||
|
@ -493,7 +493,7 @@ dwarf_gen_func_ret_location(const AOTCompContext *comp_ctx,
|
|||
const AOTFuncContext *func_ctx)
|
||||
{
|
||||
LLVMMetadataRef func_info = NULL;
|
||||
dwar_extractor *extractor;
|
||||
dwarf_extractor *extractor;
|
||||
uint64_t vm_offset;
|
||||
AOTFunc *func = func_ctx->aot_func;
|
||||
LLVMMetadataRef location_info = NULL;
|
||||
|
|
|
@ -18,7 +18,7 @@ typedef unsigned int LLDBLangType;
|
|||
|
||||
struct AOTCompData;
|
||||
typedef struct AOTCompData *aot_comp_data_t;
|
||||
typedef void *dwar_extractor_handle_t;
|
||||
typedef void *dwarf_extractor_handle_t;
|
||||
|
||||
struct AOTCompContext;
|
||||
typedef struct AOTCompContext AOTCompContext;
|
||||
|
@ -26,7 +26,7 @@ typedef struct AOTCompContext AOTCompContext;
|
|||
struct AOTFuncContext;
|
||||
|
||||
typedef struct AOTFuncContext AOTFuncContext;
|
||||
dwar_extractor_handle_t
|
||||
dwarf_extractor_handle_t
|
||||
create_dwarf_extractor(aot_comp_data_t comp_data, char *file_name);
|
||||
|
||||
LLVMMetadataRef
|
||||
|
|
|
@ -88,27 +88,28 @@ fail:
|
|||
|
||||
static int
|
||||
wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 elem_idx,
|
||||
uint32 dst, uint32 len, uint32 src)
|
||||
uint32 dst_offset, uint32 len, uint32 src_offset)
|
||||
{
|
||||
WASMTableInstance *tbl;
|
||||
uint32 tbl_sz;
|
||||
WASMTableSeg *elem;
|
||||
uint32 elem_len;
|
||||
|
||||
tbl = inst->tables[tbl_idx];
|
||||
tbl_sz = tbl->cur_size;
|
||||
if (dst > tbl_sz || tbl_sz - dst < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
elem = inst->module->table_segments + elem_idx;
|
||||
elem_len = elem->function_count;
|
||||
if (src > elem_len || elem_len - src < len)
|
||||
if (offset_len_out_of_bounds(src_offset, len, elem_len))
|
||||
goto out_of_bounds;
|
||||
|
||||
tbl = inst->tables[tbl_idx];
|
||||
tbl_sz = tbl->cur_size;
|
||||
if (offset_len_out_of_bounds(dst_offset, len, tbl_sz))
|
||||
goto out_of_bounds;
|
||||
|
||||
bh_memcpy_s((uint8 *)tbl + offsetof(WASMTableInstance, elems)
|
||||
+ dst * sizeof(uint32),
|
||||
(uint32)((tbl_sz - dst) * sizeof(uint32)),
|
||||
elem->func_indexes + src, (uint32)(len * sizeof(uint32)));
|
||||
+ dst_offset * sizeof(uint32),
|
||||
(uint32)((tbl_sz - dst_offset) * sizeof(uint32)),
|
||||
elem->func_indexes + src_offset,
|
||||
(uint32)(len * sizeof(uint32)));
|
||||
|
||||
return 0;
|
||||
out_of_bounds:
|
||||
|
@ -157,14 +158,14 @@ wasm_copy_table(WASMModuleInstance *inst, uint32 src_tbl_idx,
|
|||
WASMTableInstance *src_tbl, *dst_tbl;
|
||||
uint32 src_tbl_sz, dst_tbl_sz;
|
||||
|
||||
src_tbl = inst->tables[src_tbl_idx];
|
||||
src_tbl_sz = src_tbl->cur_size;
|
||||
if (src_offset > src_tbl_sz || src_tbl_sz - src_offset < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
dst_tbl = inst->tables[dst_tbl_idx];
|
||||
dst_tbl_sz = dst_tbl->cur_size;
|
||||
if (dst_offset > dst_tbl_sz || dst_tbl_sz - dst_offset < len)
|
||||
if (offset_len_out_of_bounds(dst_offset, len, dst_tbl_sz))
|
||||
goto out_of_bounds;
|
||||
|
||||
src_tbl = inst->tables[src_tbl_idx];
|
||||
src_tbl_sz = src_tbl->cur_size;
|
||||
if (offset_len_out_of_bounds(src_offset, len, src_tbl_sz))
|
||||
goto out_of_bounds;
|
||||
|
||||
bh_memmove_s((uint8 *)dst_tbl + offsetof(WASMTableInstance, elems)
|
||||
|
@ -263,7 +264,7 @@ fail:
|
|||
}
|
||||
|
||||
static int
|
||||
wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst,
|
||||
wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst_offset,
|
||||
uint32 val, uint32 len)
|
||||
{
|
||||
WASMTableInstance *tbl;
|
||||
|
@ -272,11 +273,11 @@ wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst,
|
|||
tbl = inst->tables[tbl_idx];
|
||||
tbl_sz = tbl->cur_size;
|
||||
|
||||
if (dst > tbl_sz || tbl_sz - dst < len)
|
||||
if (offset_len_out_of_bounds(dst_offset, len, tbl_sz))
|
||||
goto out_of_bounds;
|
||||
|
||||
for (; len != 0; dst++, len--) {
|
||||
tbl->elems[dst] = val;
|
||||
for (; len != 0; dst_offset++, len--) {
|
||||
tbl->elems[dst_offset] = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -26,8 +26,8 @@ void
|
|||
aot_destroy_comp_data(aot_comp_data_t comp_data);
|
||||
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
typedef void *dwar_extractor_handle_t;
|
||||
dwar_extractor_handle_t
|
||||
typedef void *dwarf_extractor_handle_t;
|
||||
dwarf_extractor_handle_t
|
||||
create_dwarf_extractor(aot_comp_data_t comp_data, char *file_name);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -627,7 +627,6 @@ typedef struct WASMBranchBlock {
|
|||
uint32 cell_num;
|
||||
} WASMBranchBlock;
|
||||
|
||||
/* Execution environment, e.g. stack info */
|
||||
/**
|
||||
* Align an unsigned value on a alignment boundary.
|
||||
*
|
||||
|
@ -643,6 +642,24 @@ align_uint(unsigned v, unsigned b)
|
|||
return (v + m) & ~m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a piece of data is out of range
|
||||
*
|
||||
* @param offset the offset that the data starts
|
||||
* @param len the length of the data
|
||||
* @param max_size the maximum size of the data range
|
||||
*
|
||||
* @return true if out of range, false otherwise
|
||||
*/
|
||||
inline static bool
|
||||
offset_len_out_of_bounds(uint32 offset, uint32 len, uint32 max_size)
|
||||
{
|
||||
if (offset + len < offset /* integer overflow */
|
||||
|| offset + len > max_size)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash value of c string.
|
||||
*/
|
||||
|
|
|
@ -710,28 +710,28 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min,
|
|||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint32)(*(uint8 *)maddr); \
|
||||
*(uint8 *)maddr = (uint8)(readv op sval); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint32)LOAD_U16(maddr); \
|
||||
STORE_U16(maddr, (uint16)(readv op sval)); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else { \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = LOAD_I32(maddr); \
|
||||
STORE_U32(maddr, readv op sval); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
PUSH_I32(readv); \
|
||||
break; \
|
||||
|
@ -750,39 +750,39 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min,
|
|||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint64)(*(uint8 *)maddr); \
|
||||
*(uint8 *)maddr = (uint8)(readv op sval); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint64)LOAD_U16(maddr); \
|
||||
STORE_U16(maddr, (uint16)(readv op sval)); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint64)LOAD_U32(maddr); \
|
||||
STORE_U32(maddr, (uint32)(readv op sval)); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else { \
|
||||
uint64 op_result; \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint64)LOAD_I64(maddr); \
|
||||
op_result = readv op sval; \
|
||||
STORE_I64(maddr, op_result); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
PUSH_I64(readv); \
|
||||
break; \
|
||||
|
@ -1062,21 +1062,33 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
|||
os_mutex_unlock(&exec_env->wait_lock); \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_SUSPEND_FLAGS() \
|
||||
do { \
|
||||
os_mutex_lock(&exec_env->wait_lock); \
|
||||
if (exec_env->suspend_flags.flags != 0) { \
|
||||
if (exec_env->suspend_flags.flags & 0x01) { \
|
||||
/* terminate current thread */ \
|
||||
os_mutex_unlock(&exec_env->wait_lock); \
|
||||
return; \
|
||||
} \
|
||||
while (exec_env->suspend_flags.flags & 0x02) { \
|
||||
/* suspend current thread */ \
|
||||
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
|
||||
} \
|
||||
} \
|
||||
os_mutex_unlock(&exec_env->wait_lock); \
|
||||
#if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0
|
||||
/* The lock is only needed when the suspend_flags is atomic; otherwise
|
||||
the lock is already taken at the time when SUSPENSION_LOCK() is called. */
|
||||
#define SUSPENSION_LOCK() os_mutex_lock(&exec_env->wait_lock);
|
||||
#define SUSPENSION_UNLOCK() os_mutex_unlock(&exec_env->wait_lock);
|
||||
#else
|
||||
#define SUSPENSION_LOCK()
|
||||
#define SUSPENSION_UNLOCK()
|
||||
#endif
|
||||
|
||||
#define CHECK_SUSPEND_FLAGS() \
|
||||
do { \
|
||||
WASM_SUSPEND_FLAGS_LOCK(exec_env->wait_lock); \
|
||||
if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \
|
||||
& WASM_SUSPEND_FLAG_TERMINATE) { \
|
||||
/* terminate current thread */ \
|
||||
WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
|
||||
return; \
|
||||
} \
|
||||
while (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \
|
||||
& WASM_SUSPEND_FLAG_SUSPEND) { \
|
||||
/* suspend current thread */ \
|
||||
SUSPENSION_LOCK() \
|
||||
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \
|
||||
SUSPENSION_UNLOCK() \
|
||||
} \
|
||||
WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
|
||||
} while (0)
|
||||
#endif /* WASM_ENABLE_DEBUG_INTERP */
|
||||
#endif /* WASM_ENABLE_THREAD_MGR */
|
||||
|
@ -1144,10 +1156,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
|
||||
#endif
|
||||
WASMMemoryInstance *memory = wasm_get_default_memory(module);
|
||||
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|
||||
|
@ -3235,7 +3243,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
case WASM_OP_TABLE_INIT:
|
||||
{
|
||||
uint32 tbl_idx, elem_idx;
|
||||
uint64 n, s, d;
|
||||
uint32 n, s, d;
|
||||
WASMTableInstance *tbl_inst;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, elem_idx);
|
||||
|
@ -3250,20 +3258,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
s = (uint32)POP_I32();
|
||||
d = (uint32)POP_I32();
|
||||
|
||||
/* TODO: what if the element is not passive? */
|
||||
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (n + s > module->module->table_segments[elem_idx]
|
||||
.function_count
|
||||
|| d + n > tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(
|
||||
s, n,
|
||||
module->module->table_segments[elem_idx]
|
||||
.function_count)
|
||||
|| offset_len_out_of_bounds(d, n,
|
||||
tbl_inst->cur_size)) {
|
||||
wasm_set_exception(module,
|
||||
"out of bounds table access");
|
||||
goto got_exception;
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (module->module->table_segments[elem_idx]
|
||||
.is_dropped) {
|
||||
wasm_set_exception(module,
|
||||
|
@ -3304,7 +3313,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
case WASM_OP_TABLE_COPY:
|
||||
{
|
||||
uint32 src_tbl_idx, dst_tbl_idx;
|
||||
uint64 n, s, d;
|
||||
uint32 n, s, d;
|
||||
WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx);
|
||||
|
@ -3321,8 +3330,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
s = (uint32)POP_I32();
|
||||
d = (uint32)POP_I32();
|
||||
|
||||
if (d + n > dst_tbl_inst->cur_size
|
||||
|| s + n > src_tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(d, n,
|
||||
dst_tbl_inst->cur_size)
|
||||
|| offset_len_out_of_bounds(
|
||||
s, n, src_tbl_inst->cur_size)) {
|
||||
wasm_set_exception(module,
|
||||
"out of bounds table access");
|
||||
goto got_exception;
|
||||
|
@ -3392,11 +3403,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
fill_val = POP_I32();
|
||||
i = POP_I32();
|
||||
|
||||
/* TODO: what if the element is not passive? */
|
||||
/* TODO: what if the element is dropped? */
|
||||
|
||||
if (i + n > tbl_inst->cur_size) {
|
||||
/* TODO: verify warning content */
|
||||
if (offset_len_out_of_bounds(i, n,
|
||||
tbl_inst->cur_size)) {
|
||||
wasm_set_exception(module,
|
||||
"out of bounds table access");
|
||||
goto got_exception;
|
||||
|
@ -3514,23 +3522,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint32)(*(uint8 *)maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint32)LOAD_U16(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = LOAD_I32(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
|
||||
PUSH_I32(readv);
|
||||
|
@ -3549,30 +3557,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)(*(uint8 *)maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_U16(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_U32(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = LOAD_I64(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
|
||||
PUSH_I64(readv);
|
||||
|
@ -3591,23 +3599,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
*(uint8 *)maddr = (uint8)sval;
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_U16(maddr, (uint16)sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_U32(maddr, sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3625,30 +3633,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
*(uint8 *)maddr = (uint8)sval;
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_U16(maddr, (uint16)sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_U32(maddr, (uint32)sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
PUT_I64_TO_ADDR((uint32 *)maddr, sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3668,32 +3676,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
|
||||
expect = (uint8)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint32)(*(uint8 *)maddr);
|
||||
if (readv == expect)
|
||||
*(uint8 *)maddr = (uint8)(sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
|
||||
expect = (uint16)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint32)LOAD_U16(maddr);
|
||||
if (readv == expect)
|
||||
STORE_U16(maddr, (uint16)(sval));
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = LOAD_I32(maddr);
|
||||
if (readv == expect)
|
||||
STORE_U32(maddr, sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
PUSH_I32(readv);
|
||||
break;
|
||||
|
@ -3714,43 +3722,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
|
||||
expect = (uint8)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)(*(uint8 *)maddr);
|
||||
if (readv == expect)
|
||||
*(uint8 *)maddr = (uint8)(sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
|
||||
expect = (uint16)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_U16(maddr);
|
||||
if (readv == expect)
|
||||
STORE_U16(maddr, (uint16)(sval));
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
|
||||
expect = (uint32)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_U32(maddr);
|
||||
if (readv == expect)
|
||||
STORE_U32(maddr, (uint32)(sval));
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS();
|
||||
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_I64(maddr);
|
||||
if (readv == expect)
|
||||
STORE_I64(maddr, sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
PUSH_I64(readv);
|
||||
break;
|
||||
|
@ -3783,7 +3791,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
HANDLE_OP(DEBUG_OP_BREAK)
|
||||
{
|
||||
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP);
|
||||
exec_env->suspend_flags.flags |= 2;
|
||||
WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
|
||||
WASM_SUSPEND_FLAG_SUSPEND);
|
||||
frame_ip--;
|
||||
SYNC_ALL_TO_FRAME();
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
|
|
|
@ -482,28 +482,28 @@ LOAD_PTR(void *addr)
|
|||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(1); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint32)(*(uint8 *)maddr); \
|
||||
*(uint8 *)maddr = (uint8)(readv op sval); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(2); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint32)LOAD_U16(maddr); \
|
||||
STORE_U16(maddr, (uint16)(readv op sval)); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else { \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(4); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = LOAD_I32(maddr); \
|
||||
STORE_U32(maddr, readv op sval); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
PUSH_I32(readv); \
|
||||
break; \
|
||||
|
@ -522,39 +522,39 @@ LOAD_PTR(void *addr)
|
|||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(1); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint64)(*(uint8 *)maddr); \
|
||||
*(uint8 *)maddr = (uint8)(readv op sval); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(2); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint64)LOAD_U16(maddr); \
|
||||
STORE_U16(maddr, (uint16)(readv op sval)); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(4); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint64)LOAD_U32(maddr); \
|
||||
STORE_U32(maddr, (uint32)(readv op sval)); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
else { \
|
||||
uint64 op_result; \
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(8); \
|
||||
\
|
||||
os_mutex_lock(&node->shared_mem_lock); \
|
||||
shared_memory_lock(memory); \
|
||||
readv = (uint64)LOAD_I64(maddr); \
|
||||
op_result = readv op sval; \
|
||||
STORE_I64(maddr, op_result); \
|
||||
os_mutex_unlock(&node->shared_mem_lock); \
|
||||
shared_memory_unlock(memory); \
|
||||
} \
|
||||
PUSH_I64(readv); \
|
||||
break; \
|
||||
|
@ -1065,18 +1065,17 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
|||
#endif
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#define CHECK_SUSPEND_FLAGS() \
|
||||
do { \
|
||||
os_mutex_lock(&exec_env->wait_lock); \
|
||||
if (exec_env->suspend_flags.flags != 0) { \
|
||||
if (exec_env->suspend_flags.flags & 0x01) { \
|
||||
/* terminate current thread */ \
|
||||
os_mutex_unlock(&exec_env->wait_lock); \
|
||||
return; \
|
||||
} \
|
||||
/* TODO: support suspend and breakpoint */ \
|
||||
} \
|
||||
os_mutex_unlock(&exec_env->wait_lock); \
|
||||
#define CHECK_SUSPEND_FLAGS() \
|
||||
do { \
|
||||
WASM_SUSPEND_FLAGS_LOCK(exec_env->wait_lock); \
|
||||
if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \
|
||||
& WASM_SUSPEND_FLAG_TERMINATE) { \
|
||||
/* terminate current thread */ \
|
||||
WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
|
||||
return; \
|
||||
} \
|
||||
/* TODO: support suspend and breakpoint */ \
|
||||
WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
@ -1167,10 +1166,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *node =
|
||||
wasm_module_get_shared_memory((WASMModuleCommon *)module->module);
|
||||
#endif
|
||||
WASMMemoryInstance *memory = wasm_get_default_memory(module);
|
||||
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|
||||
|
@ -3079,7 +3074,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
case WASM_OP_TABLE_INIT:
|
||||
{
|
||||
uint32 tbl_idx, elem_idx;
|
||||
uint64 n, s, d;
|
||||
uint32 n, s, d;
|
||||
WASMTableInstance *tbl_inst;
|
||||
|
||||
elem_idx = read_uint32(frame_ip);
|
||||
|
@ -3094,18 +3089,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
s = (uint32)POP_I32();
|
||||
d = (uint32)POP_I32();
|
||||
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (n + s > module->module->table_segments[elem_idx]
|
||||
.function_count
|
||||
|| d + n > tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(
|
||||
s, n,
|
||||
module->module->table_segments[elem_idx]
|
||||
.function_count)
|
||||
|| offset_len_out_of_bounds(d, n,
|
||||
tbl_inst->cur_size)) {
|
||||
wasm_set_exception(module,
|
||||
"out of bounds table access");
|
||||
goto got_exception;
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (module->module->table_segments[elem_idx]
|
||||
.is_dropped) {
|
||||
wasm_set_exception(module,
|
||||
|
@ -3144,7 +3142,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
case WASM_OP_TABLE_COPY:
|
||||
{
|
||||
uint32 src_tbl_idx, dst_tbl_idx;
|
||||
uint64 n, s, d;
|
||||
uint32 n, s, d;
|
||||
WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
|
||||
|
||||
dst_tbl_idx = read_uint32(frame_ip);
|
||||
|
@ -3161,8 +3159,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
s = (uint32)POP_I32();
|
||||
d = (uint32)POP_I32();
|
||||
|
||||
if (d + n > dst_tbl_inst->cur_size
|
||||
|| s + n > src_tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(d, n,
|
||||
dst_tbl_inst->cur_size)
|
||||
|| offset_len_out_of_bounds(
|
||||
s, n, src_tbl_inst->cur_size)) {
|
||||
wasm_set_exception(module,
|
||||
"out of bounds table access");
|
||||
goto got_exception;
|
||||
|
@ -3233,7 +3233,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
fill_val = POP_I32();
|
||||
i = POP_I32();
|
||||
|
||||
if (i + n > tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(i, n,
|
||||
tbl_inst->cur_size)) {
|
||||
wasm_set_exception(module,
|
||||
"out of bounds table access");
|
||||
goto got_exception;
|
||||
|
@ -3348,23 +3349,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(1);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint32)(*(uint8 *)maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(2);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint32)LOAD_U16(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(4);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = LOAD_I32(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
|
||||
PUSH_I32(readv);
|
||||
|
@ -3383,30 +3384,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(1);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)(*(uint8 *)maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(2);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_U16(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(4);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_U32(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(8);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = LOAD_I64(maddr);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
|
||||
PUSH_I64(readv);
|
||||
|
@ -3424,23 +3425,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (opcode == WASM_OP_ATOMIC_I32_STORE8) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(1);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
*(uint8 *)maddr = (uint8)sval;
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I32_STORE16) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(2);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_U16(maddr, (uint16)sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(4);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_U32(maddr, sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3458,30 +3459,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (opcode == WASM_OP_ATOMIC_I64_STORE8) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(1);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
*(uint8 *)maddr = (uint8)sval;
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I64_STORE16) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(2);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_U16(maddr, (uint16)sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_I64_STORE32) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(4);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_U32(maddr, (uint32)sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(8);
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
STORE_I64(maddr, sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3501,32 +3502,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
CHECK_ATOMIC_MEMORY_ACCESS(1);
|
||||
|
||||
expect = (uint8)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint32)(*(uint8 *)maddr);
|
||||
if (readv == expect)
|
||||
*(uint8 *)maddr = (uint8)(sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(2);
|
||||
|
||||
expect = (uint16)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint32)LOAD_U16(maddr);
|
||||
if (readv == expect)
|
||||
STORE_U16(maddr, (uint16)(sval));
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(4);
|
||||
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = LOAD_I32(maddr);
|
||||
if (readv == expect)
|
||||
STORE_U32(maddr, sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
PUSH_I32(readv);
|
||||
break;
|
||||
|
@ -3547,43 +3548,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
CHECK_ATOMIC_MEMORY_ACCESS(1);
|
||||
|
||||
expect = (uint8)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)(*(uint8 *)maddr);
|
||||
if (readv == expect)
|
||||
*(uint8 *)maddr = (uint8)(sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(2);
|
||||
|
||||
expect = (uint16)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_U16(maddr);
|
||||
if (readv == expect)
|
||||
STORE_U16(maddr, (uint16)(sval));
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(4);
|
||||
|
||||
expect = (uint32)expect;
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_U32(maddr);
|
||||
if (readv == expect)
|
||||
STORE_U32(maddr, (uint32)(sval));
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
else {
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
|
||||
CHECK_ATOMIC_MEMORY_ACCESS(8);
|
||||
|
||||
os_mutex_lock(&node->shared_mem_lock);
|
||||
shared_memory_lock(memory);
|
||||
readv = (uint64)LOAD_I64(maddr);
|
||||
if (readv == expect)
|
||||
STORE_I64(maddr, sval);
|
||||
os_mutex_unlock(&node->shared_mem_lock);
|
||||
shared_memory_unlock(memory);
|
||||
}
|
||||
PUSH_I64(readv);
|
||||
break;
|
||||
|
|
|
@ -7014,6 +7014,7 @@ static bool
|
|||
copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
bool ret = false;
|
||||
int16 *frame_offset = NULL;
|
||||
uint8 *cells = NULL, cell;
|
||||
int16 *src_offsets = NULL;
|
||||
|
@ -7084,13 +7085,13 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
|
|||
if (is_if_block)
|
||||
PUSH_OFFSET_TYPE(VALUE_TYPE_I32);
|
||||
|
||||
ret = true;
|
||||
|
||||
fail:
|
||||
/* Free the emit data */
|
||||
wasm_runtime_free(emit_data);
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -8065,7 +8066,8 @@ re_scan:
|
|||
uint8 vec_len, ref_type;
|
||||
|
||||
read_leb_uint32(p, p_end, vec_len);
|
||||
if (!vec_len) {
|
||||
if (vec_len != 1) {
|
||||
/* typed select must have exactly one result */
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"invalid result arity");
|
||||
goto fail;
|
||||
|
|
|
@ -6235,7 +6235,8 @@ re_scan:
|
|||
uint8 vec_len, ref_type;
|
||||
|
||||
read_leb_uint32(p, p_end, vec_len);
|
||||
if (!vec_len) {
|
||||
if (vec_len != 1) {
|
||||
/* typed select must have exactly one result */
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"invalid result arity");
|
||||
goto fail;
|
||||
|
|
|
@ -122,11 +122,8 @@ memories_deinstantiate(WASMModuleInstance *module_inst,
|
|||
}
|
||||
#endif
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (memories[i]->is_shared) {
|
||||
int32 ref_count = shared_memory_dec_reference(
|
||||
(WASMModuleCommon *)module_inst->module);
|
||||
bh_assert(ref_count >= 0);
|
||||
|
||||
if (shared_memory_is_shared(memories[i])) {
|
||||
uint32 ref_count = shared_memory_dec_reference(memories[i]);
|
||||
/* if the reference count is not zero,
|
||||
don't free the memory */
|
||||
if (ref_count > 0)
|
||||
|
@ -159,7 +156,8 @@ memories_deinstantiate(WASMModuleInstance *module_inst,
|
|||
}
|
||||
|
||||
static WASMMemoryInstance *
|
||||
memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory,
|
||||
memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent,
|
||||
WASMMemoryInstance *memory, uint32 memory_idx,
|
||||
uint32 num_bytes_per_page, uint32 init_page_count,
|
||||
uint32 max_page_count, uint32 heap_size, uint32 flags,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
|
@ -180,22 +178,11 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory,
|
|||
bool is_shared_memory = flags & 0x02 ? true : false;
|
||||
|
||||
/* shared memory */
|
||||
if (is_shared_memory) {
|
||||
WASMSharedMemNode *node = wasm_module_get_shared_memory(
|
||||
(WASMModuleCommon *)module_inst->module);
|
||||
/* If the memory of this module has been instantiated,
|
||||
return the memory instance directly */
|
||||
if (node) {
|
||||
uint32 ref_count;
|
||||
ref_count = shared_memory_inc_reference(
|
||||
(WASMModuleCommon *)module_inst->module);
|
||||
bh_assert(ref_count > 0);
|
||||
memory = (WASMMemoryInstance *)shared_memory_get_memory_inst(node);
|
||||
bh_assert(memory);
|
||||
|
||||
(void)ref_count;
|
||||
return memory;
|
||||
}
|
||||
if (is_shared_memory && parent != NULL) {
|
||||
bh_assert(parent->memory_count > memory_idx);
|
||||
memory = parent->memories[memory_idx];
|
||||
shared_memory_inc_reference(memory);
|
||||
return memory;
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_SHARED_MEMORY */
|
||||
|
||||
|
@ -388,24 +375,13 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory,
|
|||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (is_shared_memory) {
|
||||
memory->is_shared = true;
|
||||
if (!shared_memory_set_memory_inst(
|
||||
(WASMModuleCommon *)module_inst->module,
|
||||
(WASMMemoryInstanceCommon *)memory)) {
|
||||
set_error_buf(error_buf, error_buf_size, "allocate memory failed");
|
||||
goto fail4;
|
||||
}
|
||||
memory->ref_count = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_VERBOSE("Memory instantiate success.");
|
||||
return memory;
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
fail4:
|
||||
if (heap_size > 0)
|
||||
mem_allocator_destroy(memory->heap_handle);
|
||||
#endif
|
||||
fail3:
|
||||
if (heap_size > 0)
|
||||
wasm_runtime_free(memory->heap_handle);
|
||||
|
@ -428,7 +404,8 @@ fail1:
|
|||
*/
|
||||
static WASMMemoryInstance **
|
||||
memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
|
||||
uint32 heap_size, char *error_buf, uint32 error_buf_size)
|
||||
WASMModuleInstance *parent, uint32 heap_size,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
WASMImport *import;
|
||||
uint32 mem_index = 0, i,
|
||||
|
@ -474,26 +451,29 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
|
|||
else
|
||||
#endif
|
||||
{
|
||||
if (!(memories[mem_index++] = memory_instantiate(
|
||||
module_inst, memory, num_bytes_per_page, init_page_count,
|
||||
max_page_count, actual_heap_size, flags, error_buf,
|
||||
error_buf_size))) {
|
||||
if (!(memories[mem_index] = memory_instantiate(
|
||||
module_inst, parent, memory, mem_index,
|
||||
num_bytes_per_page, init_page_count, max_page_count,
|
||||
actual_heap_size, flags, error_buf, error_buf_size))) {
|
||||
memories_deinstantiate(module_inst, memories, memory_count);
|
||||
return NULL;
|
||||
}
|
||||
mem_index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* instantiate memories from memory section */
|
||||
for (i = 0; i < module->memory_count; i++, memory++) {
|
||||
if (!(memories[mem_index++] = memory_instantiate(
|
||||
module_inst, memory, module->memories[i].num_bytes_per_page,
|
||||
if (!(memories[mem_index] = memory_instantiate(
|
||||
module_inst, parent, memory, mem_index,
|
||||
module->memories[i].num_bytes_per_page,
|
||||
module->memories[i].init_page_count,
|
||||
module->memories[i].max_page_count, heap_size,
|
||||
module->memories[i].flags, error_buf, error_buf_size))) {
|
||||
memories_deinstantiate(module_inst, memories, memory_count);
|
||||
return NULL;
|
||||
}
|
||||
mem_index++;
|
||||
}
|
||||
|
||||
bh_assert(mem_index == memory_count);
|
||||
|
@ -1104,10 +1084,14 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
if (initialize_func
|
||||
&& !wasm_call_function(exec_env, initialize_func, 0, NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
(void)initialize_func;
|
||||
#endif
|
||||
|
||||
if (post_inst_func
|
||||
&& !wasm_call_function(exec_env, post_inst_func, 0, NULL)) {
|
||||
|
@ -1297,7 +1281,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst,
|
|||
WASMModuleInstance *sub_module_inst = NULL;
|
||||
|
||||
sub_module_inst =
|
||||
wasm_instantiate(sub_module, false, NULL, stack_size, heap_size,
|
||||
wasm_instantiate(sub_module, NULL, NULL, stack_size, heap_size,
|
||||
error_buf, error_buf_size);
|
||||
if (!sub_module_inst) {
|
||||
LOG_DEBUG("instantiate %s failed",
|
||||
|
@ -1642,7 +1626,7 @@ wasm_set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode)
|
|||
* Instantiate module
|
||||
*/
|
||||
WASMModuleInstance *
|
||||
wasm_instantiate(WASMModule *module, bool is_sub_inst,
|
||||
wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
|
||||
WASMExecEnv *exec_env_main, uint32 stack_size,
|
||||
uint32 heap_size, char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
|
@ -1659,6 +1643,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
|
|||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
bool ret = false;
|
||||
#endif
|
||||
const bool is_sub_inst = parent != NULL;
|
||||
|
||||
if (!module)
|
||||
return NULL;
|
||||
|
@ -1777,8 +1762,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
|
|||
|
||||
/* Instantiate memories/tables/functions */
|
||||
if ((module_inst->memory_count > 0
|
||||
&& !(module_inst->memories = memories_instantiate(
|
||||
module, module_inst, heap_size, error_buf, error_buf_size)))
|
||||
&& !(module_inst->memories =
|
||||
memories_instantiate(module, module_inst, parent, heap_size,
|
||||
error_buf, error_buf_size)))
|
||||
|| (module_inst->table_count > 0
|
||||
&& !(module_inst->tables =
|
||||
tables_instantiate(module, module_inst, first_table,
|
||||
|
@ -2212,16 +2198,6 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
|
|||
sub_module_deinstantiate(module_inst);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
/* Destroy wasi resource before freeing app heap, since some fields of
|
||||
wasi contex are allocated from app heap, and if app heap is freed,
|
||||
these fields will be set to NULL, we cannot free their internal data
|
||||
which may allocated from global heap. */
|
||||
/* Only destroy wasi ctx in the main module instance */
|
||||
if (!is_sub_inst)
|
||||
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
|
||||
#endif
|
||||
|
||||
if (module_inst->memory_count > 0)
|
||||
memories_deinstantiate(module_inst, module_inst->memories,
|
||||
module_inst->memory_count);
|
||||
|
@ -2254,10 +2230,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
|
|||
if (module_inst->e->c_api_func_imports)
|
||||
wasm_runtime_free(module_inst->e->c_api_func_imports);
|
||||
|
||||
if (!is_sub_inst) {
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
|
||||
#endif
|
||||
#if WASM_ENABLE_WASI_NN != 0
|
||||
if (!is_sub_inst)
|
||||
wasi_nn_destroy(module_inst);
|
||||
#endif
|
||||
}
|
||||
|
||||
wasm_runtime_free(module_inst);
|
||||
}
|
||||
|
@ -3297,13 +3277,13 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx,
|
|||
bh_assert(tbl_inst);
|
||||
bh_assert(tbl_seg);
|
||||
|
||||
if (!length) {
|
||||
if (offset_len_out_of_bounds(src_offset, length, tbl_seg->function_count)
|
||||
|| offset_len_out_of_bounds(dst_offset, length, tbl_inst->cur_size)) {
|
||||
jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (length + src_offset > tbl_seg->function_count
|
||||
|| dst_offset + length > tbl_inst->cur_size) {
|
||||
jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
if (!length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3345,8 +3325,9 @@ llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx,
|
|||
bh_assert(src_tbl_inst);
|
||||
bh_assert(dst_tbl_inst);
|
||||
|
||||
if ((uint64)dst_offset + length > dst_tbl_inst->cur_size
|
||||
|| (uint64)src_offset + length > src_tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(dst_offset, length, dst_tbl_inst->cur_size)
|
||||
|| offset_len_out_of_bounds(src_offset, length,
|
||||
src_tbl_inst->cur_size)) {
|
||||
jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
@ -3378,7 +3359,7 @@ llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx,
|
|||
tbl_inst = wasm_get_table_inst(module_inst, tbl_idx);
|
||||
bh_assert(tbl_inst);
|
||||
|
||||
if (data_offset + length > tbl_inst->cur_size) {
|
||||
if (offset_len_out_of_bounds(data_offset, length, tbl_inst->cur_size)) {
|
||||
jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define _WASM_RUNTIME_H
|
||||
|
||||
#include "wasm.h"
|
||||
#include "bh_atomic.h"
|
||||
#include "bh_hashmap.h"
|
||||
#include "../common/wasm_runtime_common.h"
|
||||
#include "../common/wasm_exec_env.h"
|
||||
|
@ -79,7 +80,7 @@ struct WASMMemoryInstance {
|
|||
/* Module type */
|
||||
uint32 module_type;
|
||||
/* Shared memory flag */
|
||||
bool is_shared;
|
||||
bh_atomic_32_t ref_count; /* 0: non-shared, > 0: reference count */
|
||||
|
||||
/* Number bytes per page */
|
||||
uint32 num_bytes_per_page;
|
||||
|
@ -400,7 +401,7 @@ void
|
|||
wasm_unload(WASMModule *module);
|
||||
|
||||
WASMModuleInstance *
|
||||
wasm_instantiate(WASMModule *module, bool is_sub_inst,
|
||||
wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
|
||||
WASMExecEnv *exec_env_main, uint32 stack_size,
|
||||
uint32 heap_size, char *error_buf, uint32 error_buf_size);
|
||||
|
||||
|
|
|
@ -531,7 +531,8 @@ pthread_start_routine(void *arg)
|
|||
else {
|
||||
info_node->u.ret = (void *)(uintptr_t)argv[0];
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
if (exec_env->suspend_flags.flags & 0x08)
|
||||
if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
|
||||
& WASM_SUSPEND_FLAG_EXIT)
|
||||
/* argv[0] isn't set after longjmp(1) to
|
||||
invoke_native_with_hw_bound_check */
|
||||
info_node->u.ret = exec_env->thread_ret_value;
|
||||
|
@ -580,7 +581,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
|
|||
#endif
|
||||
|
||||
if (!(new_module_inst = wasm_runtime_instantiate_internal(
|
||||
module, true, exec_env, stack_size, 0, NULL, 0)))
|
||||
module, module_inst, exec_env, stack_size, 0, NULL, 0)))
|
||||
return -1;
|
||||
|
||||
/* Set custom_data to new module instance */
|
||||
|
@ -690,6 +691,14 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread,
|
|||
bh_assert(node->joinable);
|
||||
join_ret = 0;
|
||||
ret = node->u.ret;
|
||||
|
||||
/* The target thread changes the node's status before calling
|
||||
wasm_cluster_exit_thread to exit, so here its resources may
|
||||
haven't been destroyed yet, we wait enough time to ensure that
|
||||
they are actually destroyed to avoid unexpected behavior. */
|
||||
os_mutex_lock(&exec_env->wait_lock);
|
||||
os_cond_reltimedwait(&exec_env->wait_cond, &exec_env->wait_lock, 1000);
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
}
|
||||
|
||||
if (retval_offset != 0)
|
||||
|
@ -757,7 +766,6 @@ __pthread_self_wrapper(wasm_exec_env_t exec_env)
|
|||
static void
|
||||
pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
|
||||
{
|
||||
wasm_module_inst_t module_inst = get_module_inst(exec_env);
|
||||
ThreadRoutineArgs *args = get_thread_arg(exec_env);
|
||||
/* Currently exit main thread is not allowed */
|
||||
if (!args)
|
||||
|
@ -775,9 +783,6 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
|
|||
/* destroy pthread key values */
|
||||
call_key_destructor(exec_env);
|
||||
|
||||
/* routine exit, destroy instance */
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
|
||||
if (!args->info_node->joinable) {
|
||||
delete_thread_info_node(args->info_node);
|
||||
}
|
||||
|
@ -789,6 +794,8 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
|
|||
|
||||
wasm_runtime_free(args);
|
||||
|
||||
/* Don't destroy exec_env->module_inst in this functuntion since
|
||||
it will be destroyed in wasm_cluster_exit_thread */
|
||||
wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ test_nslookup_mt(void *params)
|
|||
{
|
||||
int *af = (int *)params;
|
||||
test_nslookup(*af);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#ifdef __wasi__
|
||||
#include <wasi/api.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -12,105 +14,123 @@
|
|||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SERVER_MSG "Message from server."
|
||||
#define PORT 8989
|
||||
pthread_mutex_t mut;
|
||||
pthread_cond_t cond;
|
||||
|
||||
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
int server_init_complete = 0;
|
||||
char buffer[sizeof(SERVER_MSG) + 1];
|
||||
|
||||
struct socket_info {
|
||||
union {
|
||||
struct sockaddr_in addr_ipv4;
|
||||
struct sockaddr_in6 addr_ipv6;
|
||||
} addr;
|
||||
typedef struct {
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len;
|
||||
int sock;
|
||||
};
|
||||
|
||||
struct thread_args {
|
||||
int family;
|
||||
int protocol;
|
||||
};
|
||||
} socket_info_t;
|
||||
|
||||
struct socket_info
|
||||
init_socket_addr(int family, int protocol)
|
||||
void
|
||||
wait_for_server(int wait_time_seconds)
|
||||
{
|
||||
int sock = socket(family, protocol, 0);
|
||||
assert(sock != -1);
|
||||
int res = 0;
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += wait_time_seconds;
|
||||
|
||||
struct socket_info info;
|
||||
if (family == AF_INET) {
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
info.addr.addr_ipv4 = addr;
|
||||
pthread_mutex_lock(&mut);
|
||||
while (server_init_complete == 0) {
|
||||
res = pthread_cond_timedwait(&cond, &mut, &ts);
|
||||
if (res == ETIMEDOUT)
|
||||
break;
|
||||
}
|
||||
else if (family == AF_INET6) {
|
||||
struct sockaddr_in6 addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(PORT);
|
||||
addr.sin6_addr = in6addr_loopback;
|
||||
info.addr.addr_ipv6 = addr;
|
||||
}
|
||||
info.sock = sock;
|
||||
return info;
|
||||
pthread_mutex_unlock(&mut);
|
||||
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void
|
||||
assert_thread_args(struct thread_args *args)
|
||||
notify_server_started()
|
||||
{
|
||||
assert(args->family == AF_INET || args->family == AF_INET6);
|
||||
assert(args->protocol == SOCK_STREAM || args->protocol == SOCK_DGRAM);
|
||||
pthread_mutex_lock(&mut);
|
||||
server_init_complete = 1;
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&mut);
|
||||
}
|
||||
|
||||
socket_info_t
|
||||
init_socket_addr(int family, int protocol)
|
||||
{
|
||||
socket_info_t info;
|
||||
|
||||
info.sock = socket(family, protocol, 0);
|
||||
assert(info.sock != -1);
|
||||
info.protocol = protocol;
|
||||
|
||||
memset(&info.addr, 0, sizeof(info.addr));
|
||||
|
||||
if (family == AF_INET) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&info.addr;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(PORT);
|
||||
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
info.addr_len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
else if (family == AF_INET6) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&info.addr;
|
||||
addr->sin6_family = AF_INET6;
|
||||
addr->sin6_port = htons(PORT);
|
||||
addr->sin6_addr = in6addr_loopback;
|
||||
info.addr_len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void *
|
||||
server(void *arg)
|
||||
{
|
||||
server_init_complete = 0;
|
||||
struct thread_args *args = (struct thread_args *)arg;
|
||||
assert_thread_args(args);
|
||||
|
||||
struct socket_info init_server_sock =
|
||||
init_socket_addr(args->family, args->protocol);
|
||||
|
||||
int server_sock = init_server_sock.sock;
|
||||
socklen_t addr_size;
|
||||
char buffer[sizeof(SERVER_MSG) + 1] = { 0 };
|
||||
struct sockaddr_storage client_addr;
|
||||
strcpy(buffer, SERVER_MSG);
|
||||
socket_info_t *info = (socket_info_t *)arg;
|
||||
struct sockaddr *server_addr = (struct sockaddr *)&info->addr;
|
||||
int server_sock = info->sock;
|
||||
|
||||
struct sockaddr *server_addr = (struct sockaddr *)&init_server_sock.addr;
|
||||
int ret = bind(server_sock, server_addr,
|
||||
args->family == AF_INET ? sizeof(struct sockaddr_in)
|
||||
: sizeof(struct sockaddr_in6));
|
||||
assert(ret == 0);
|
||||
int optval = 1;
|
||||
assert(setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval,
|
||||
sizeof(optval))
|
||||
== 0);
|
||||
|
||||
(args->protocol == SOCK_STREAM) && listen(server_sock, 1);
|
||||
pthread_mutex_lock(&mut);
|
||||
server_init_complete = 1;
|
||||
pthread_mutex_unlock(&mut);
|
||||
pthread_cond_signal(&cond);
|
||||
assert(bind(server_sock, server_addr, info->addr_len) == 0);
|
||||
|
||||
addr_size = sizeof(client_addr);
|
||||
if (args->protocol == SOCK_STREAM) {
|
||||
if (info->protocol == SOCK_STREAM)
|
||||
listen(server_sock, 1);
|
||||
notify_server_started();
|
||||
|
||||
socklen_t addr_size = info->addr_len;
|
||||
if (info->protocol == SOCK_STREAM) {
|
||||
int client_sock =
|
||||
accept(server_sock, (struct sockaddr *)&client_addr, &addr_size);
|
||||
assert(client_sock >= 0);
|
||||
sendto(client_sock, buffer, strlen(buffer), 0,
|
||||
(struct sockaddr *)&client_addr, addr_size);
|
||||
|
||||
assert(close(client_sock) == 0);
|
||||
assert(recv(client_sock, buffer, sizeof(buffer), 0) > 0);
|
||||
strcpy(buffer, SERVER_MSG);
|
||||
assert(send(client_sock, buffer, sizeof(buffer), 0) > 0);
|
||||
assert(recv(client_sock, buffer, sizeof(buffer), 0) > 0);
|
||||
}
|
||||
else {
|
||||
recvfrom(server_sock, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr *)&client_addr, &addr_size);
|
||||
sendto(server_sock, buffer, strlen(buffer), 0,
|
||||
(struct sockaddr *)&client_addr, addr_size);
|
||||
|
||||
assert(close(server_sock) == 0);
|
||||
assert(recvfrom(server_sock, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr *)&client_addr, &addr_size)
|
||||
> 0);
|
||||
strcpy(buffer, SERVER_MSG);
|
||||
assert(sendto(server_sock, buffer, strlen(buffer), 0,
|
||||
(struct sockaddr *)&client_addr, addr_size)
|
||||
> 0);
|
||||
assert(recvfrom(server_sock, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr *)&client_addr, &addr_size)
|
||||
> 0);
|
||||
}
|
||||
assert(close(server_sock) == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -118,46 +138,23 @@ server(void *arg)
|
|||
void *
|
||||
client(void *arg)
|
||||
{
|
||||
struct thread_args *args = (struct thread_args *)arg;
|
||||
assert_thread_args(args);
|
||||
char buffer[sizeof(SERVER_MSG) + 1];
|
||||
socket_info_t *info = (socket_info_t *)arg;
|
||||
int sock = info->sock;
|
||||
struct sockaddr *addr = (struct sockaddr *)&info->addr;
|
||||
|
||||
pthread_mutex_lock(&mut);
|
||||
wait_for_server(1);
|
||||
|
||||
while (server_init_complete == 0) {
|
||||
pthread_cond_wait(&cond, &mut);
|
||||
if (info->protocol == SOCK_STREAM) {
|
||||
assert(connect(sock, addr, info->addr_len) != -1);
|
||||
}
|
||||
|
||||
struct socket_info init_client_sock =
|
||||
init_socket_addr(args->family, args->protocol);
|
||||
int sock = init_client_sock.sock;
|
||||
pthread_mutex_unlock(&mut);
|
||||
|
||||
if (args->family == AF_INET) {
|
||||
struct sockaddr_in addr = init_client_sock.addr.addr_ipv4;
|
||||
if (args->protocol == SOCK_STREAM) {
|
||||
assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1);
|
||||
}
|
||||
else {
|
||||
assert(sendto(sock, buffer, strlen(buffer), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr))
|
||||
!= -1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct sockaddr_in6 addr = init_client_sock.addr.addr_ipv6;
|
||||
if (args->protocol == SOCK_STREAM) {
|
||||
assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1);
|
||||
}
|
||||
else {
|
||||
assert(sendto(sock, buffer, strlen(buffer), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr))
|
||||
!= -1);
|
||||
}
|
||||
}
|
||||
|
||||
recv(sock, buffer, sizeof(buffer), 0);
|
||||
assert(strcmp(buffer, SERVER_MSG) == 0);
|
||||
assert(sendto(sock, "open", strlen("open"), 0, addr, info->addr_len) > 0);
|
||||
assert(recv(sock, buffer, sizeof(buffer), 0) > 0);
|
||||
assert(strncmp(buffer, SERVER_MSG, strlen(SERVER_MSG)) == 0);
|
||||
assert(sendto(sock, "close", sizeof("close"), 0, addr, info->addr_len) > 0);
|
||||
assert(close(sock) == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -165,17 +162,19 @@ void
|
|||
test_protocol(int family, int protocol)
|
||||
{
|
||||
pthread_t server_thread, client_thread;
|
||||
assert(pthread_cond_init(&cond, NULL) == 0);
|
||||
assert(pthread_mutex_init(&mut, NULL) == 0);
|
||||
socket_info_t server_info = init_socket_addr(family, protocol);
|
||||
socket_info_t client_info = init_socket_addr(family, protocol);
|
||||
|
||||
struct thread_args args = { family, protocol };
|
||||
assert(pthread_create(&server_thread, NULL, server, (void *)&args) == 0);
|
||||
assert(pthread_create(&client_thread, NULL, client, (void *)&args) == 0);
|
||||
printf("Testing address family: %d protocol: %d\n", family, protocol);
|
||||
|
||||
server_init_complete = 0;
|
||||
|
||||
assert(pthread_create(&server_thread, NULL, server, (void *)&server_info)
|
||||
== 0);
|
||||
assert(pthread_create(&client_thread, NULL, client, (void *)&client_info)
|
||||
== 0);
|
||||
assert(pthread_join(server_thread, NULL) == 0);
|
||||
assert(pthread_join(client_thread, NULL) == 0);
|
||||
|
||||
assert(pthread_mutex_destroy(&mut) == 0);
|
||||
assert(pthread_cond_destroy(&cond) == 0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -190,4 +189,4 @@ main(int argc, char **argv)
|
|||
test_protocol(AF_INET6, SOCK_DGRAM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg)
|
|||
stack_size = ((WASMModuleInstance *)module_inst)->default_wasm_stack_size;
|
||||
|
||||
if (!(new_module_inst = wasm_runtime_instantiate_internal(
|
||||
module, true, exec_env, stack_size, 0, NULL, 0)))
|
||||
module, module_inst, exec_env, stack_size, 0, NULL, 0)))
|
||||
return -1;
|
||||
|
||||
wasm_runtime_set_custom_data_internal(
|
||||
|
|
|
@ -9,10 +9,13 @@ set -eo pipefail
|
|||
CC=${CC:=/opt/wasi-sdk/bin/clang}
|
||||
WAMR_DIR=../../../../..
|
||||
|
||||
# Stress tests names
|
||||
thread_start_file_exclusions=("spawn_stress_test.wasm" "linear_memory_size_update.wasm")
|
||||
|
||||
for test_c in *.c; do
|
||||
test_wasm="$(basename $test_c .c).wasm"
|
||||
|
||||
if [ $test_wasm = "linear_memory_size_update.wasm" ]; then
|
||||
if [[ " ${thread_start_file_exclusions[@]} " =~ " ${test_wasm} " ]] ; then
|
||||
thread_start_file=""
|
||||
else
|
||||
thread_start_file=$WAMR_DIR/samples/wasi-threads/wasm-apps/wasi_thread_start.S
|
||||
|
|
3
core/iwasm/libraries/lib-wasi-threads/test/manifest.json
Normal file
3
core/iwasm/libraries/lib-wasi-threads/test/manifest.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"name": "lib-wasi-threads tests"
|
||||
}
|
5
core/iwasm/libraries/lib-wasi-threads/test/skip.json
Normal file
5
core/iwasm/libraries/lib-wasi-threads/test/skip.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"lib-wasi-threads tests": {
|
||||
"spawn_stress_test": "Stress tests are incompatible with the other part and executed differently"
|
||||
}
|
||||
}
|
114
core/iwasm/libraries/lib-wasi-threads/test/spawn_stress_test.c
Normal file
114
core/iwasm/libraries/lib-wasi-threads/test/spawn_stress_test.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef __wasi__
|
||||
#error This example only compiles to WASM/WASI target
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum CONSTANTS {
|
||||
NUM_ITER = 100000,
|
||||
NUM_RETRY = 5,
|
||||
MAX_NUM_THREADS = 8,
|
||||
};
|
||||
|
||||
unsigned prime_numbers_count = 0;
|
||||
|
||||
bool
|
||||
is_prime(unsigned int num)
|
||||
{
|
||||
for (unsigned int i = 2; i <= (unsigned int)(sqrt(num)); ++i) {
|
||||
if (num % i == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *
|
||||
check_if_prime(void *value)
|
||||
{
|
||||
unsigned int *num = (unsigned int *)(value);
|
||||
usleep(10000);
|
||||
if (is_prime(*num)) {
|
||||
__atomic_fetch_add(&prime_numbers_count, 1, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
validate()
|
||||
{
|
||||
unsigned int counter = 0;
|
||||
for (unsigned int i = 2; i <= NUM_ITER; ++i) {
|
||||
counter += is_prime(i);
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
void
|
||||
spawn_thread(pthread_t *thread, unsigned int *arg)
|
||||
{
|
||||
int status_code = -1;
|
||||
for (int tries = 0; status_code != 0 && tries < NUM_RETRY; ++tries) {
|
||||
status_code = pthread_create(thread, NULL, &check_if_prime, arg);
|
||||
assert(status_code == 0 || status_code == EAGAIN);
|
||||
if (status_code == EAGAIN) {
|
||||
usleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
assert(status_code == 0 && "Thread creation should succeed");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
pthread_t threads[MAX_NUM_THREADS];
|
||||
unsigned int args[MAX_NUM_THREADS];
|
||||
double percentage = 0.1;
|
||||
|
||||
for (unsigned int factorised_number = 2; factorised_number < NUM_ITER;
|
||||
++factorised_number) {
|
||||
if (factorised_number > NUM_ITER * percentage) {
|
||||
fprintf(stderr, "Stress test is %d%% finished\n",
|
||||
(unsigned int)(percentage * 100));
|
||||
percentage += 0.1;
|
||||
}
|
||||
|
||||
unsigned int thread_num = factorised_number % MAX_NUM_THREADS;
|
||||
if (threads[thread_num] != 0) {
|
||||
assert(pthread_join(threads[thread_num], NULL) == 0);
|
||||
}
|
||||
|
||||
args[thread_num] = factorised_number;
|
||||
|
||||
usleep(2000);
|
||||
spawn_thread(&threads[thread_num], &args[thread_num]);
|
||||
assert(threads[thread_num] != 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_NUM_THREADS; ++i) {
|
||||
assert(threads[i] == 0 || pthread_join(threads[i], NULL) == 0);
|
||||
}
|
||||
|
||||
// Check the test results
|
||||
assert(
|
||||
prime_numbers_count == validate()
|
||||
&& "Answer mismatch between tested code and reference implementation");
|
||||
|
||||
fprintf(stderr, "Stress test finished successfully\n");
|
||||
return 0;
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
set (LIBC_WASI_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
set (LIBUV_VERSION v1.44.2)
|
||||
set (LIBUV_VERSION v1.46.0)
|
||||
|
||||
add_definitions (-DWASM_ENABLE_LIBC_WASI=1 -DWASM_ENABLE_UVWASI=1)
|
||||
|
||||
|
|
|
@ -509,7 +509,7 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
|
|||
#endif
|
||||
|
||||
if (!(new_module_inst = wasm_runtime_instantiate_internal(
|
||||
module, true, exec_env, stack_size, 0, NULL, 0))) {
|
||||
module, module_inst, exec_env, stack_size, 0, NULL, 0))) {
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
|
@ -606,7 +606,8 @@ thread_manager_start_routine(void *arg)
|
|||
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
os_mutex_lock(&exec_env->wait_lock);
|
||||
if (exec_env->suspend_flags.flags & 0x08)
|
||||
if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
|
||||
& WASM_SUSPEND_FLAG_EXIT)
|
||||
ret = exec_env->thread_ret_value;
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
#endif
|
||||
|
@ -993,7 +994,9 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
|
|||
if (exec_env->jmpbuf_stack_top) {
|
||||
/* Store the return value in exec_env */
|
||||
exec_env->thread_ret_value = retval;
|
||||
exec_env->suspend_flags.flags |= 0x08;
|
||||
|
||||
WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
|
||||
WASM_SUSPEND_FLAG_EXIT);
|
||||
|
||||
#ifndef BH_PLATFORM_WINDOWS
|
||||
/* Pop all jmpbuf_node except the last one */
|
||||
|
@ -1055,7 +1058,8 @@ set_thread_cancel_flags(WASMExecEnv *exec_env)
|
|||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
|
||||
#endif
|
||||
exec_env->suspend_flags.flags |= 0x01;
|
||||
WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
|
||||
WASM_SUSPEND_FLAG_TERMINATE);
|
||||
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
}
|
||||
|
@ -1178,7 +1182,8 @@ void
|
|||
wasm_cluster_suspend_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
/* Set the suspend flag */
|
||||
exec_env->suspend_flags.flags |= 0x02;
|
||||
WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags,
|
||||
WASM_SUSPEND_FLAG_SUSPEND);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1214,7 +1219,8 @@ wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
|
|||
void
|
||||
wasm_cluster_resume_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
exec_env->suspend_flags.flags &= ~0x02;
|
||||
WASM_SUSPEND_FLAGS_FETCH_AND(exec_env->suspend_flags,
|
||||
~WASM_SUSPEND_FLAG_SUSPEND);
|
||||
os_cond_signal(&exec_env->wait_cond);
|
||||
}
|
||||
|
||||
|
@ -1248,10 +1254,8 @@ set_exception_visitor(void *node, void *user_data)
|
|||
|
||||
/* Only spread non "wasi proc exit" exception */
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *shared_mem_node = wasm_module_get_shared_memory(
|
||||
(WASMModuleCommon *)curr_wasm_inst->module);
|
||||
if (shared_mem_node)
|
||||
os_mutex_lock(&shared_mem_node->shared_mem_lock);
|
||||
if (curr_wasm_inst->memory_count > 0)
|
||||
shared_memory_lock(curr_wasm_inst->memories[0]);
|
||||
#endif
|
||||
if (!strstr(wasm_inst->cur_exception, "wasi proc exit")) {
|
||||
bh_memcpy_s(curr_wasm_inst->cur_exception,
|
||||
|
@ -1260,8 +1264,8 @@ set_exception_visitor(void *node, void *user_data)
|
|||
sizeof(wasm_inst->cur_exception));
|
||||
}
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (shared_mem_node)
|
||||
os_mutex_unlock(&shared_mem_node->shared_mem_lock);
|
||||
if (curr_wasm_inst->memory_count > 0)
|
||||
shared_memory_unlock(curr_wasm_inst->memories[0]);
|
||||
#endif
|
||||
|
||||
/* Terminate the thread so it can exit from dead loops */
|
||||
|
@ -1280,15 +1284,13 @@ clear_exception_visitor(void *node, void *user_data)
|
|||
(WASMModuleInstance *)get_module_inst(curr_exec_env);
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
WASMSharedMemNode *shared_mem_node = wasm_module_get_shared_memory(
|
||||
(WASMModuleCommon *)curr_wasm_inst->module);
|
||||
if (shared_mem_node)
|
||||
os_mutex_lock(&shared_mem_node->shared_mem_lock);
|
||||
if (curr_wasm_inst->memory_count > 0)
|
||||
shared_memory_lock(curr_wasm_inst->memories[0]);
|
||||
#endif
|
||||
curr_wasm_inst->cur_exception[0] = '\0';
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
if (shared_mem_node)
|
||||
os_mutex_unlock(&shared_mem_node->shared_mem_lock);
|
||||
if (curr_wasm_inst->memory_count > 0)
|
||||
shared_memory_unlock(curr_wasm_inst->memories[0]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -1343,8 +1345,10 @@ bool
|
|||
wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env)
|
||||
{
|
||||
os_mutex_lock(&exec_env->wait_lock);
|
||||
bool is_thread_terminated =
|
||||
(exec_env->suspend_flags.flags & 0x01) ? true : false;
|
||||
bool is_thread_terminated = (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags)
|
||||
& WASM_SUSPEND_FLAG_TERMINATE)
|
||||
? true
|
||||
: false;
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
|
||||
return is_thread_terminated;
|
||||
|
|
|
@ -5,16 +5,34 @@
|
|||
|
||||
#include "platform_api_vmcore.h"
|
||||
#include "platform_api_extension.h"
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
#include "soc/mmu.h"
|
||||
#include "rom/cache.h"
|
||||
|
||||
#define MEM_DUAL_BUS_OFFSET (IRAM0_CACHE_ADDRESS_LOW - DRAM0_CACHE_ADDRESS_LOW)
|
||||
|
||||
#define in_ibus_ext(addr) \
|
||||
(((uint32)addr >= IRAM0_CACHE_ADDRESS_LOW) \
|
||||
&& ((uint32)addr < IRAM0_CACHE_ADDRESS_HIGH))
|
||||
|
||||
static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#endif
|
||||
|
||||
void *
|
||||
os_mmap(void *hint, size_t size, int prot, int flags)
|
||||
{
|
||||
if (prot & MMAP_PROT_EXEC) {
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
uint32_t mem_caps = MALLOC_CAP_SPIRAM;
|
||||
#else
|
||||
uint32_t mem_caps = MALLOC_CAP_EXEC;
|
||||
#endif
|
||||
|
||||
// Memory allocation with MALLOC_CAP_EXEC will return 4-byte aligned
|
||||
// Reserve extra 4 byte to fixup alignment and size for the pointer to
|
||||
// the originally allocated address
|
||||
void *buf_origin =
|
||||
heap_caps_malloc(size + 4 + sizeof(uintptr_t), MALLOC_CAP_EXEC);
|
||||
heap_caps_malloc(size + 4 + sizeof(uintptr_t), mem_caps);
|
||||
if (!buf_origin) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -25,19 +43,35 @@ os_mmap(void *hint, size_t size, int prot, int flags)
|
|||
|
||||
uintptr_t *addr_field = buf_fixed - sizeof(uintptr_t);
|
||||
*addr_field = (uintptr_t)buf_origin;
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
return buf_fixed + MEM_DUAL_BUS_OFFSET;
|
||||
#else
|
||||
return buf_fixed;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
return os_malloc(size);
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
uint32_t mem_caps = MALLOC_CAP_SPIRAM;
|
||||
#else
|
||||
uint32_t mem_caps = MALLOC_CAP_8BIT;
|
||||
#endif
|
||||
return heap_caps_malloc(size, mem_caps);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
os_munmap(void *addr, size_t size)
|
||||
{
|
||||
char *ptr = (char *)addr;
|
||||
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
if (in_ibus_ext(ptr)) {
|
||||
ptr -= MEM_DUAL_BUS_OFFSET;
|
||||
}
|
||||
#endif
|
||||
// We don't need special handling of the executable allocations
|
||||
// here, free() of esp-idf handles it properly
|
||||
return os_free(addr);
|
||||
return os_free(ptr);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -47,5 +81,34 @@ os_mprotect(void *addr, size_t size, int prot)
|
|||
}
|
||||
|
||||
void
|
||||
os_dcache_flush()
|
||||
{}
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
IRAM_ATTR
|
||||
#endif
|
||||
os_dcache_flush()
|
||||
{
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
uint32_t preload;
|
||||
extern void Cache_WriteBack_All(void);
|
||||
|
||||
portENTER_CRITICAL(&s_spinlock);
|
||||
|
||||
Cache_WriteBack_All();
|
||||
preload = Cache_Disable_ICache();
|
||||
Cache_Enable_ICache(preload);
|
||||
|
||||
portEXIT_CRITICAL(&s_spinlock);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
void *
|
||||
os_get_dbus_mirror(void *ibus)
|
||||
{
|
||||
if (in_ibus_ext(ibus)) {
|
||||
return (void *)((char *)ibus - MEM_DUAL_BUS_OFFSET);
|
||||
}
|
||||
else {
|
||||
return ibus;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,3 +11,9 @@ include_directories(${PLATFORM_SHARED_DIR}/../include)
|
|||
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
|
||||
|
||||
set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE})
|
||||
|
||||
# If enable PSRAM of ESP32-S3, it had better to put AOT into PSRAM, so that
|
||||
# users can use SRAM to for Wi-Fi/BLE and peripheral driver.
|
||||
if(CONFIG_ESP32S3_SPIRAM_SUPPORT)
|
||||
add_definitions(-DWASM_MEM_DUAL_BUS_MIRROR=1)
|
||||
endif()
|
||||
|
|
|
@ -129,6 +129,11 @@ os_munmap(void *addr, size_t size);
|
|||
int
|
||||
os_mprotect(void *addr, size_t size, int prot);
|
||||
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
void *
|
||||
os_get_dbus_mirror(void *ibus);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Flush cpu data cache, in some CPUs, after applying relocation to the
|
||||
* AOT code, the code may haven't been written back to the cpu data cache,
|
||||
|
|
|
@ -10,6 +10,46 @@
|
|||
#include <nuttx/arch.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_CHIP_ESP32S3)
|
||||
/*
|
||||
* TODO: Move these methods below the operating system level
|
||||
*/
|
||||
#define MEM_DUAL_BUS_OFFSET (0x42000000 - 0x3C000000)
|
||||
#define IRAM0_CACHE_ADDRESS_LOW 0x42000000
|
||||
#define IRAM0_CACHE_ADDRESS_HIGH 0x44000000
|
||||
#define IRAM_ATTR locate_data(".iram1")
|
||||
|
||||
#define in_ibus_ext(addr) \
|
||||
(((uint32)addr >= IRAM0_CACHE_ADDRESS_LOW) \
|
||||
&& ((uint32)addr < IRAM0_CACHE_ADDRESS_HIGH))
|
||||
void IRAM_ATTR
|
||||
bus_sync(void)
|
||||
{
|
||||
extern void cache_writeback_all(void);
|
||||
extern uint32_t Cache_Disable_ICache(void);
|
||||
extern void Cache_Enable_ICache(uint32_t autoload);
|
||||
|
||||
irqstate_t flags;
|
||||
uint32_t preload;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
cache_writeback_all();
|
||||
preload = Cache_Disable_ICache();
|
||||
Cache_Enable_ICache(preload);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
#else
|
||||
#define MEM_DUAL_BUS_OFFSET (0)
|
||||
#define IRAM0_CACHE_ADDRESS_LOW (0)
|
||||
#define IRAM0_CACHE_ADDRESS_HIGH (0)
|
||||
#define in_ibus_ext(addr) (0)
|
||||
static void
|
||||
bus_sync(void)
|
||||
{}
|
||||
#endif
|
||||
|
||||
int
|
||||
bh_platform_init()
|
||||
{
|
||||
|
@ -47,6 +87,10 @@ os_dumps_proc_mem_info(char *out, unsigned int size)
|
|||
void *
|
||||
os_mmap(void *hint, size_t size, int prot, int flags)
|
||||
{
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
void *i_addr, *d_addr;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
|
||||
if ((prot & MMAP_PROT_EXEC) != 0) {
|
||||
return up_textheap_memalign(sizeof(void *), size);
|
||||
|
@ -55,6 +99,17 @@ os_mmap(void *hint, size_t size, int prot, int flags)
|
|||
|
||||
if ((uint64)size >= UINT32_MAX)
|
||||
return NULL;
|
||||
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
if ((prot & MMAP_PROT_EXEC) != 0) {
|
||||
d_addr = malloc((uint32)size);
|
||||
if (d_addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
i_addr = (void *)((uint8 *)d_addr + MEM_DUAL_BUS_OFFSET);
|
||||
return in_ibus_ext(i_addr) ? i_addr : d_addr;
|
||||
}
|
||||
#endif
|
||||
return malloc((uint32)size);
|
||||
}
|
||||
|
||||
|
@ -67,7 +122,14 @@ os_munmap(void *addr, size_t size)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
return free(addr);
|
||||
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
if (in_ibus_ext(addr)) {
|
||||
free((void *)((uint8 *)addr - MEM_DUAL_BUS_OFFSET));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
free(addr);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -78,7 +140,22 @@ os_mprotect(void *addr, size_t size, int prot)
|
|||
|
||||
void
|
||||
os_dcache_flush()
|
||||
{}
|
||||
{
|
||||
bus_sync();
|
||||
}
|
||||
|
||||
#if (WASM_MEM_DUAL_BUS_MIRROR != 0)
|
||||
void *
|
||||
os_get_dbus_mirror(void *ibus)
|
||||
{
|
||||
if (in_ibus_ext(ibus)) {
|
||||
return (void *)((uint8 *)ibus - MEM_DUAL_BUS_OFFSET);
|
||||
}
|
||||
else {
|
||||
return ibus;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If AT_FDCWD is provided, maybe we have openat family */
|
||||
#if !defined(AT_FDCWD)
|
||||
|
|
123
core/shared/utils/bh_atomic.h
Normal file
123
core/shared/utils/bh_atomic.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Amazon Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _BH_ATOMIC_H
|
||||
#define _BH_ATOMIC_H
|
||||
|
||||
#include "gnuc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Why don't we use C11 stdatomics here?
|
||||
*
|
||||
* Unlike C11 stdatomics,
|
||||
*
|
||||
* - bh_atomic_xxx_t is guaranteed to have the same size as the base type.
|
||||
* Thus more friendly to our AOT conventions.
|
||||
*
|
||||
* - It's available for C++.
|
||||
* Although C++23 will have C-compatible stdatomics.h, it isn't widely
|
||||
* available yet.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note about BH_ATOMIC_32_IS_ATOMIC
|
||||
*
|
||||
* If BH_ATOMIC_32_IS_ATOMIC == 0, BH_ATOMIC_xxx operations defined below
|
||||
* are not really atomic and require an external lock.
|
||||
*
|
||||
* Expected usage is:
|
||||
*
|
||||
* bh_atomic_32_t var = 0;
|
||||
* uint32 old;
|
||||
* #if BH_ATOMIC_32_IS_ATOMIC == 0
|
||||
* lock(&some_lock);
|
||||
* #endif
|
||||
* old = BH_ATOMIC_32_FETCH_AND(var, 1);
|
||||
* #if BH_ATOMIC_32_IS_ATOMIC == 0
|
||||
* unlock(&some_lock);
|
||||
* #endif
|
||||
*/
|
||||
|
||||
typedef uint32 bh_atomic_32_t;
|
||||
|
||||
#if defined(__GNUC_PREREQ)
|
||||
#if __GNUC_PREREQ(4, 7)
|
||||
#define CLANG_GCC_HAS_ATOMIC_BUILTIN
|
||||
#endif
|
||||
#elif defined(__clang__)
|
||||
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 0)
|
||||
#define CLANG_GCC_HAS_ATOMIC_BUILTIN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CLANG_GCC_HAS_ATOMIC_BUILTIN)
|
||||
#define BH_ATOMIC_32_IS_ATOMIC 1
|
||||
#define BH_ATOMIC_32_LOAD(v) __atomic_load_n(&(v), __ATOMIC_SEQ_CST)
|
||||
#define BH_ATOMIC_32_FETCH_OR(v, val) \
|
||||
__atomic_fetch_or(&(v), (val), __ATOMIC_SEQ_CST)
|
||||
#define BH_ATOMIC_32_FETCH_AND(v, val) \
|
||||
__atomic_fetch_and(&(v), (val), __ATOMIC_SEQ_CST)
|
||||
#define BH_ATOMIC_32_FETCH_ADD(v, val) \
|
||||
__atomic_fetch_add(&(v), (val), __ATOMIC_SEQ_CST)
|
||||
#define BH_ATOMIC_32_FETCH_SUB(v, val) \
|
||||
__atomic_fetch_sub(&(v), (val), __ATOMIC_SEQ_CST)
|
||||
#else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */
|
||||
#define BH_ATOMIC_32_LOAD(v) (v)
|
||||
#define BH_ATOMIC_32_FETCH_OR(v, val) nonatomic_32_fetch_or(&(v), val)
|
||||
#define BH_ATOMIC_32_FETCH_AND(v, val) nonatomic_32_fetch_and(&(v), val)
|
||||
#define BH_ATOMIC_32_FETCH_ADD(v, val) nonatomic_32_fetch_add(&(v), val)
|
||||
#define BH_ATOMIC_32_FETCH_SUB(v, val) nonatomic_32_fetch_sub(&(v), val)
|
||||
|
||||
static inline uint32
|
||||
nonatomic_32_fetch_or(bh_atomic_32_t *p, uint32 val)
|
||||
{
|
||||
uint32 old = *p;
|
||||
*p |= val;
|
||||
return old;
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
nonatomic_32_fetch_and(bh_atomic_32_t *p, uint32 val)
|
||||
{
|
||||
uint32 old = *p;
|
||||
*p &= val;
|
||||
return old;
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
nonatomic_32_fetch_add(bh_atomic_32_t *p, uint32 val)
|
||||
{
|
||||
uint32 old = *p;
|
||||
*p += val;
|
||||
return old;
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
nonatomic_32_fetch_sub(bh_atomic_32_t *p, uint32 val)
|
||||
{
|
||||
uint32 old = *p;
|
||||
*p -= val;
|
||||
return old;
|
||||
}
|
||||
|
||||
/* The flag can be defined by the user if the platform
|
||||
supports atomic access to uint32 aligned memory. */
|
||||
#ifdef WASM_UINT32_IS_ATOMIC
|
||||
#define BH_ATOMIC_32_IS_ATOMIC 1
|
||||
#else /* else of WASM_UINT32_IS_ATOMIC */
|
||||
#define BH_ATOMIC_32_IS_ATOMIC 0
|
||||
#endif /* WASM_UINT32_IS_ATOMIC */
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* end of _BH_ATOMIC_H */
|
|
@ -258,68 +258,69 @@ We can't pass structure data or class objects through the pointer since the memo
|
|||
|
||||
## Execute wasm functions in multiple threads
|
||||
|
||||
The `exec_env` is not thread safety, it will cause unexpected behavior if the same `exec_env` is used in multiple threads. However, we've provided two ways to execute wasm functions concurrently:
|
||||
It isn't safe to use an `exec_env` object in multiple threads concurrently.
|
||||
To run a multi-threaded application, you basically need a separate `exec_env`
|
||||
for each threads.
|
||||
|
||||
- You can use `pthread` APIs in your wasm application, see [pthread library](./pthread_library.md) for more details.
|
||||
### Approaches to manage `exec_env` objects and threads
|
||||
|
||||
- The `spawn exec_env` and `spawn thread` APIs are available, you can use these APIs to manage the threads in native:
|
||||
WAMR supports two approaches to manage `exec_env` and threads as described
|
||||
below. While they are not exclusive, you usually only need to use one of
|
||||
them.
|
||||
|
||||
*spawn exec_env:*
|
||||
#### Make your WASM application manage threads
|
||||
|
||||
`spawn exec_env` API spawns a `new_exec_env` base on the original `exec_env`, use can use it in other threads:
|
||||
You can make your WASM application spawn threads by itself,
|
||||
typically using `pthread` APIs like `pthread_create`.
|
||||
See [pthread library](./pthread_library.md) and
|
||||
[pthread implementations](./pthread_impls.md) for more details.
|
||||
In this case, WAMR manages `exec_env` for the spawned threads.
|
||||
|
||||
#### Make your embedder manage threads
|
||||
|
||||
The `spawn exec_env` and `spawn thread` APIs are available for the embedder.
|
||||
You can use these APIs to manage the threads.
|
||||
See [Thread related embedder API](./embed_wamr_spawn_api.md) for details.
|
||||
|
||||
### Other notes about threads
|
||||
|
||||
* You can manage the maximum number of threads
|
||||
|
||||
```C
|
||||
new_exec_env = wasm_runtime_spawn_exec_env(exec_env);
|
||||
|
||||
/* Then you can use new_exec_env in your new thread */
|
||||
module_inst = wasm_runtime_get_module_inst(new_exec_env);
|
||||
func_inst = wasm_runtime_lookup_function(module_inst, ...);
|
||||
wasm_runtime_call_wasm(new_exec_env, func_inst, ...);
|
||||
|
||||
/* you need to use this API to manually destroy the spawned exec_env */
|
||||
wasm_runtime_destroy_spawned_exec_env(new_exec_env);
|
||||
init_args.max_thread_num = THREAD_NUM;
|
||||
/* If this init argument is not set, the default maximum thread number is 4 */
|
||||
```
|
||||
|
||||
*spawn thread:*
|
||||
* To share memory among threads, you need to build your WASM application with shared memory
|
||||
|
||||
You can also use `spawn thread` API to avoid manually manage the spawned exec_env:
|
||||
|
||||
```C
|
||||
wasm_thread_t wasm_tid;
|
||||
void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg)
|
||||
{
|
||||
module_inst = wasm_runtime_get_module_inst(exec_env);
|
||||
func_inst = wasm_runtime_lookup_function(module_inst, ...);
|
||||
wasm_runtime_call_wasm(exec_env, func_inst, ...);
|
||||
}
|
||||
wasm_runtime_spawn_thread(exec_env, &wasm_tid, wamr_thread_cb, NULL);
|
||||
/* Use wasm_runtime_join_thread to join the spawned thread */
|
||||
wasm_runtime_join_thread(wasm_tid, NULL);
|
||||
```
|
||||
|
||||
**Note1: You can manage the maximum number of threads can be created:**
|
||||
|
||||
```C
|
||||
init_args.max_thread_num = THREAD_NUM;
|
||||
/* If this init argument is not set, the default maximum thread number is 4 */
|
||||
```
|
||||
|
||||
**Note2: The wasm application should be built with `--shared-memory` and `-pthread` enabled:**
|
||||
|
||||
```bash
|
||||
/opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread \
|
||||
-Wl,--shared-memory,--max-memory=131072 \
|
||||
-Wl,--no-entry,--export=__heap_base,--export=__data_end \
|
||||
-Wl,--export=__wasm_call_ctors,--export=${your_func_name}
|
||||
```
|
||||
|
||||
**Note3: The pthread library feature should be enabled while building the runtime:**
|
||||
For example, it can be done with `--shared-memory` and `-pthread`.
|
||||
|
||||
```bash
|
||||
cmake .. -DWAMR_BUILD_LIB_PTHREAD=1
|
||||
/opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread \
|
||||
-Wl,--shared-memory,--max-memory=131072 \
|
||||
-Wl,--no-entry,--export=__heap_base,--export=__data_end \
|
||||
-Wl,--export=__wasm_call_ctors,--export=${your_func_name}
|
||||
```
|
||||
|
||||
[Here](../samples/spawn-thread) is a sample to show how to use these APIs.
|
||||
* The corresponding threading feature should be enabled while building the runtime
|
||||
|
||||
- WAMR lib-pthread (legacy)
|
||||
|
||||
```bash
|
||||
cmake .. -DWAMR_BUILD_LIB_PTHREAD=1
|
||||
```
|
||||
|
||||
- wasi-threads
|
||||
|
||||
```bash
|
||||
cmake .. -DWAMR_BUILD_LIB_WASI_THREADS=1
|
||||
```
|
||||
|
||||
- `wasm_runtime_spawn_exec_env` and `wasm_runtime_spawn_thread`
|
||||
|
||||
```bash
|
||||
cmake .. -DWAMR_BUILD_THREAD_MGR=1 -DWAMR_BUILD_SHARED_MEMORY=1
|
||||
```
|
||||
|
||||
## The deinitialization procedure
|
||||
|
||||
|
|
38
doc/embed_wamr_spawn_api.md
Normal file
38
doc/embed_wamr_spawn_api.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Thread related embedder API
|
||||
|
||||
This document explains `wasm_runtime_spawn_exec_env` and
|
||||
`wasm_runtime_spawn_thread`.
|
||||
[Here](../samples/spawn-thread) is a sample to show how to use these APIs.
|
||||
|
||||
* spawn exec_env
|
||||
|
||||
`spawn exec_env` API creates a new `exec_env` based on the original `exec_env`. You can use it in other threads. It's up to the embedder how to manage host threads to run the new `exec_env`.
|
||||
|
||||
```C
|
||||
new_exec_env = wasm_runtime_spawn_exec_env(exec_env);
|
||||
|
||||
/* Then you can use new_exec_env in your new thread */
|
||||
module_inst = wasm_runtime_get_module_inst(new_exec_env);
|
||||
func_inst = wasm_runtime_lookup_function(module_inst, ...);
|
||||
wasm_runtime_call_wasm(new_exec_env, func_inst, ...);
|
||||
|
||||
/* you need to use this API to manually destroy the spawned exec_env */
|
||||
wasm_runtime_destroy_spawned_exec_env(new_exec_env);
|
||||
```
|
||||
|
||||
* spawn thread
|
||||
|
||||
Alternatively, you can use `spawn thread` API to avoid managing the extra exec_env and the corresponding host thread manually:
|
||||
|
||||
```C
|
||||
wasm_thread_t wasm_tid;
|
||||
void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg)
|
||||
{
|
||||
module_inst = wasm_runtime_get_module_inst(exec_env);
|
||||
func_inst = wasm_runtime_lookup_function(module_inst, ...);
|
||||
wasm_runtime_call_wasm(exec_env, func_inst, ...);
|
||||
}
|
||||
wasm_runtime_spawn_thread(exec_env, &wasm_tid, wamr_thread_cb, NULL);
|
||||
/* Use wasm_runtime_join_thread to join the spawned thread */
|
||||
wasm_runtime_join_thread(wasm_tid, NULL);
|
||||
```
|
|
@ -5,14 +5,16 @@
|
|||
|
||||
ESP32_TARGET="esp32"
|
||||
ESP32C3_TARGET="esp32c3"
|
||||
ESP32S3_TARGET="esp32s3"
|
||||
|
||||
usage ()
|
||||
{
|
||||
echo "USAGE:"
|
||||
echo "$0 $ESP32_TARGET|$ESP32C3_TARGET"
|
||||
echo "$0 $ESP32_TARGET|$ESP32C3_TARGET|$ESP32S3_TARGET"
|
||||
echo "Example:"
|
||||
echo " $0 $ESP32_TARGET"
|
||||
echo " $0 $ESP32C3_TARGET"
|
||||
echo " $0 $ESP32S3_TARGET"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||
#define IWASM_MAIN_STACK_SIZE 5120
|
||||
#else
|
||||
#define IWASM_MAIN_STACK_SIZE 4096
|
||||
#endif
|
||||
|
||||
#define LOG_TAG "wamr"
|
||||
|
||||
static void *
|
||||
|
@ -146,7 +152,7 @@ app_main(void)
|
|||
pthread_attr_t tattr;
|
||||
pthread_attr_init(&tattr);
|
||||
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
|
||||
pthread_attr_setstacksize(&tattr, 4096);
|
||||
pthread_attr_setstacksize(&tattr, IWASM_MAIN_STACK_SIZE);
|
||||
|
||||
res = pthread_create(&t, &tattr, iwasm_main, (void *)NULL);
|
||||
assert(res == 0);
|
||||
|
|
|
@ -92,6 +92,8 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
|
|||
snprintf(error_buf, error_buf_size, "%s", string);
|
||||
}
|
||||
|
||||
static bool runtime_inited = false;
|
||||
|
||||
static void
|
||||
handle_cmd_init_runtime(uint64 *args, uint32 argc)
|
||||
{
|
||||
|
@ -100,6 +102,12 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc)
|
|||
|
||||
bh_assert(argc == 1);
|
||||
|
||||
/* avoid duplicated init */
|
||||
if (runtime_inited) {
|
||||
args[0] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
os_set_print_function(enclave_print);
|
||||
|
||||
max_thread_num = (uint32)args[0];
|
||||
|
@ -122,6 +130,7 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc)
|
|||
return;
|
||||
}
|
||||
|
||||
runtime_inited = true;
|
||||
args[0] = true;
|
||||
|
||||
LOG_VERBOSE("Init runtime environment success.\n");
|
||||
|
@ -130,7 +139,11 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc)
|
|||
static void
|
||||
handle_cmd_destroy_runtime()
|
||||
{
|
||||
if (!runtime_inited)
|
||||
return;
|
||||
|
||||
wasm_runtime_destroy();
|
||||
runtime_inited = false;
|
||||
|
||||
LOG_VERBOSE("Destroy runtime success.\n");
|
||||
}
|
||||
|
@ -214,6 +227,11 @@ handle_cmd_load_module(uint64 *args, uint32 argc)
|
|||
|
||||
bh_assert(argc == 4);
|
||||
|
||||
if (!runtime_inited) {
|
||||
*(void **)args_org = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_xip_file((uint8 *)wasm_file, wasm_file_size)) {
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(enclave_module = (EnclaveModule *)wasm_runtime_malloc(
|
||||
|
@ -284,6 +302,10 @@ handle_cmd_unload_module(uint64 *args, uint32 argc)
|
|||
|
||||
bh_assert(argc == 1);
|
||||
|
||||
if (!runtime_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_LIB_RATS != 0
|
||||
/* Remove enclave module from enclave module list */
|
||||
os_mutex_lock(&enclave_module_list_lock);
|
||||
|
@ -354,6 +376,11 @@ handle_cmd_instantiate_module(uint64 *args, uint32 argc)
|
|||
|
||||
bh_assert(argc == 5);
|
||||
|
||||
if (!runtime_inited) {
|
||||
*(void **)args_org = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(module_inst =
|
||||
wasm_runtime_instantiate(enclave_module->module, stack_size,
|
||||
heap_size, error_buf, error_buf_size))) {
|
||||
|
@ -373,6 +400,10 @@ handle_cmd_deinstantiate_module(uint64 *args, uint32 argc)
|
|||
|
||||
bh_assert(argc == 1);
|
||||
|
||||
if (!runtime_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
wasm_runtime_deinstantiate(module_inst);
|
||||
|
||||
LOG_VERBOSE("Deinstantiate module success.\n");
|
||||
|
@ -389,6 +420,11 @@ handle_cmd_get_exception(uint64 *args, uint32 argc)
|
|||
|
||||
bh_assert(argc == 3);
|
||||
|
||||
if (!runtime_inited) {
|
||||
args_org[0] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((exception1 = wasm_runtime_get_exception(module_inst))) {
|
||||
snprintf(exception, exception_size, "%s", exception1);
|
||||
args_org[0] = true;
|
||||
|
@ -410,6 +446,10 @@ handle_cmd_exec_app_main(uint64 *args, int32 argc)
|
|||
bh_assert(argc >= 3);
|
||||
bh_assert(app_argc >= 1);
|
||||
|
||||
if (!runtime_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
total_size = sizeof(char *) * (app_argc > 2 ? (uint64)app_argc : 2);
|
||||
|
||||
if (total_size >= UINT32_MAX
|
||||
|
@ -439,6 +479,10 @@ handle_cmd_exec_app_func(uint64 *args, int32 argc)
|
|||
|
||||
bh_assert(argc == app_argc + 3);
|
||||
|
||||
if (!runtime_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
total_size = sizeof(char *) * (app_argc > 2 ? (uint64)app_argc : 2);
|
||||
|
||||
if (total_size >= UINT32_MAX
|
||||
|
@ -488,6 +532,11 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
|
|||
|
||||
bh_assert(argc == 10);
|
||||
|
||||
if (!runtime_inited) {
|
||||
*args_org = false;
|
||||
return;
|
||||
}
|
||||
|
||||
total_size += sizeof(char *) * (uint64)dir_list_size
|
||||
+ sizeof(char *) * (uint64)env_list_size
|
||||
+ sizeof(char *) * (uint64)addr_pool_list_size
|
||||
|
@ -610,6 +659,11 @@ handle_cmd_get_pgo_prof_buf_size(uint64 *args, int32 argc)
|
|||
|
||||
bh_assert(argc == 1);
|
||||
|
||||
if (!runtime_inited) {
|
||||
args[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
buf_len = wasm_runtime_get_pgo_prof_data_size(module_inst);
|
||||
args[0] = buf_len;
|
||||
}
|
||||
|
@ -625,6 +679,11 @@ handle_cmd_get_pro_prof_buf_data(uint64 *args, int32 argc)
|
|||
|
||||
bh_assert(argc == 3);
|
||||
|
||||
if (!runtime_inited) {
|
||||
args_org[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
bytes_dumped =
|
||||
wasm_runtime_dump_pgo_prof_data_to_buf(module_inst, buf, len);
|
||||
args_org[0] = bytes_dumped;
|
||||
|
@ -704,6 +763,11 @@ ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size)
|
|||
char error_buf[128];
|
||||
const char *exception;
|
||||
|
||||
/* avoid duplicated init */
|
||||
if (runtime_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
os_set_print_function(enclave_print);
|
||||
|
||||
memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
||||
|
|
|
@ -141,6 +141,12 @@ else
|
|||
CFLAGS += -DWASM_ENABLE_WORD_ALIGN_READ=0
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INTERPRETERS_WAMR_MEM_DUAL_BUS_MIRROR),y)
|
||||
CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=1
|
||||
else
|
||||
CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=0
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INTERPRETERS_WAMR_FAST), y)
|
||||
CFLAGS += -DWASM_ENABLE_FAST_INTERP=1
|
||||
CFLAGS += -DWASM_ENABLE_INTERP=1
|
||||
|
|
20
samples/bh_atomic/CMakeLists.txt
Normal file
20
samples/bh_atomic/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Copyright (C) 2023 Midokura Japan KK. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(bh_atomic)
|
||||
|
||||
string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
|
||||
if(APPLE)
|
||||
add_definitions(-DBH_PLATFORM_DARWIN)
|
||||
endif()
|
||||
|
||||
set(WAMR_BUILD_INTERP 1)
|
||||
set(WAMR_BUILD_LIBC_BUILTIN 0)
|
||||
|
||||
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
|
||||
include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
|
||||
add_executable(bh_atomic main.c)
|
||||
|
||||
target_link_libraries(bh_atomic)
|
42
samples/bh_atomic/main.c
Normal file
42
samples/bh_atomic/main.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Midokura Japan KK. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "bh_platform.h"
|
||||
#include "bh_atomic.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
bh_atomic_32_t v;
|
||||
uint32 o;
|
||||
|
||||
v = 0x00ff00ff;
|
||||
o = BH_ATOMIC_32_LOAD(v);
|
||||
assert(o == 0x00ff00ff);
|
||||
|
||||
v = 0x00ff00ff;
|
||||
o = BH_ATOMIC_32_FETCH_OR(v, 0xffff0000);
|
||||
assert(o == 0x00ff00ff);
|
||||
assert(v == 0xffff00ff);
|
||||
|
||||
v = 0x00ff00ff;
|
||||
o = BH_ATOMIC_32_FETCH_AND(v, 0xffff0000);
|
||||
assert(o == 0x00ff00ff);
|
||||
assert(v == 0x00ff0000);
|
||||
|
||||
v = 0x00ff00ff;
|
||||
o = BH_ATOMIC_32_FETCH_ADD(v, 0x10101);
|
||||
assert(o == 0x00ff00ff);
|
||||
assert(v == 0x00ff00ff + 0x10101);
|
||||
|
||||
v = 0x00ff00ff;
|
||||
o = BH_ATOMIC_32_FETCH_SUB(v, 0x10101);
|
||||
assert(o == 0x00ff00ff);
|
||||
assert(v == 0x00ff00ff - 0x10101);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,147 +1,198 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required (VERSION 3.0)
|
||||
cmake_minimum_required (VERSION 3.14)
|
||||
|
||||
project(xnnpack_wasm)
|
||||
|
||||
################ EMCC ################
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(xnnpack
|
||||
# grep xnnpack_benchmark -A 1 BUILD.bazel \
|
||||
# | grep "name =" \
|
||||
# | awk '{print $3}' \
|
||||
# | sed -e 's/\"//g; s/,//g; s/^/\"/g; s/$/\"/g'
|
||||
list(APPEND NATIVE_BENCHMARKS
|
||||
"qs8_dwconv_bench"
|
||||
"qs8_f32_vcvt_bench"
|
||||
"qs8_gemm_bench"
|
||||
"qs8_requantization_bench"
|
||||
"qs8_vadd_bench"
|
||||
"qs8_vaddc_bench"
|
||||
"qs8_vcvt_bench"
|
||||
"qs16_qs8_vcvt_bench"
|
||||
"qs8_vlrelu_bench"
|
||||
"qs8_vmul_bench"
|
||||
"qs8_vmulc_bench"
|
||||
"qu8_f32_vcvt_bench"
|
||||
"qu8_gemm_bench"
|
||||
"qu8_requantization_bench"
|
||||
"qu8_vadd_bench"
|
||||
"qu8_vaddc_bench"
|
||||
"qu8_vcvt_bench"
|
||||
"qu8_vlrelu_bench"
|
||||
"qu8_vmul_bench"
|
||||
"qu8_vmulc_bench"
|
||||
"bf16_gemm_bench"
|
||||
"f16_f32acc_igemm_bench"
|
||||
"f16_igemm_bench"
|
||||
"f16_f32acc_gemm_bench"
|
||||
"f16_gemm_bench"
|
||||
"f16_raddstoreexpminusmax_bench"
|
||||
"f16_spmm_bench"
|
||||
"f16_vsigmoid_bench"
|
||||
"f16_vtanh_bench"
|
||||
"f16_f32_vcvt_bench"
|
||||
"f32_igemm_bench"
|
||||
"f32_conv_hwc_bench"
|
||||
"f16_conv_hwc2chw_bench"
|
||||
"f16_gavgpool_cw_bench"
|
||||
"f32_gavgpool_cw_bench"
|
||||
"f32_conv_hwc2chw_bench"
|
||||
"f16_dwconv_bench"
|
||||
"f32_dwconv_bench"
|
||||
"f32_dwconv2d_chw_bench"
|
||||
"f16_dwconv2d_chw_bench"
|
||||
"f32_f16_vcvt_bench"
|
||||
"xx_transpose_bench"
|
||||
"x8_transpose_bench"
|
||||
"x16_transpose_bench"
|
||||
"x24_transpose_bench"
|
||||
"x32_transpose_bench"
|
||||
"x64_transpose_bench"
|
||||
"f32_bgemm_bench"
|
||||
"f32_gemm_bench"
|
||||
"f32_qs8_vcvt_bench"
|
||||
"f32_qu8_vcvt_bench"
|
||||
"f32_raddexpminusmax_bench"
|
||||
"f32_raddextexp_bench"
|
||||
"f32_raddstoreexpminusmax_bench"
|
||||
"f32_rmax_bench"
|
||||
"f32_spmm_bench"
|
||||
"f32_softmax_bench"
|
||||
"f16_velu_bench"
|
||||
"f32_velu_bench"
|
||||
"f32_vhswish_bench"
|
||||
"f32_vlrelu_bench"
|
||||
"f32_vrelu_bench"
|
||||
"f32_vscaleexpminusmax_bench"
|
||||
"f32_vscaleextexp_bench"
|
||||
"f32_vsigmoid_bench"
|
||||
"f16_vsqrt_bench"
|
||||
"f32_vsqrt_bench"
|
||||
"f32_vtanh_bench"
|
||||
"f32_im2col_gemm_bench"
|
||||
"rounding_bench"
|
||||
"s16_rmaxabs_bench"
|
||||
"s16_window_bench"
|
||||
"u32_filterbank_accumulate_bench"
|
||||
"u32_filterbank_subtract_bench"
|
||||
"u32_vlog_bench"
|
||||
"u64_u32_vsqrtshift_bench"
|
||||
"i16_vlshift_bench"
|
||||
"cs16_vsquareabs_bench"
|
||||
"cs16_bfly4_bench"
|
||||
"cs16_fftr_bench"
|
||||
"x8_lut_bench"
|
||||
"x32_packw_bench"
|
||||
"x16_packw_bench"
|
||||
"abs_bench"
|
||||
"average_pooling_bench"
|
||||
"bankers_rounding_bench"
|
||||
"ceiling_bench"
|
||||
"channel_shuffle_bench"
|
||||
"convert_bench"
|
||||
"convolution_bench"
|
||||
"deconvolution_bench"
|
||||
"elu_bench"
|
||||
"floor_bench"
|
||||
"global_average_pooling_bench"
|
||||
"hardswish_bench"
|
||||
"leaky_relu_bench"
|
||||
"max_pooling_bench"
|
||||
"negate_bench"
|
||||
"prelu_bench"
|
||||
"sigmoid_bench"
|
||||
"softmax_bench"
|
||||
"square_bench"
|
||||
"square_root_bench"
|
||||
"tanh_bench"
|
||||
"truncation_bench"
|
||||
"f16_dwconv_e2e_bench"
|
||||
"f16_gemm_e2e_bench"
|
||||
"f32_dwconv_e2e_bench"
|
||||
"f32_gemm_e2e_bench"
|
||||
"qs8_dwconv_e2e_bench"
|
||||
"qs8_gemm_e2e_bench"
|
||||
"qu8_gemm_e2e_bench"
|
||||
"qu8_dwconv_e2e_bench"
|
||||
"end2end_bench"
|
||||
"f16_exp_ulp_eval"
|
||||
"f16_expminus_ulp_eval"
|
||||
"f16_expm1minus_ulp_eval"
|
||||
"f16_sigmoid_ulp_eval"
|
||||
"f16_sqrt_ulp_eval"
|
||||
"f16_tanh_ulp_eval"
|
||||
"f32_exp_ulp_eval"
|
||||
"f32_expminus_ulp_eval"
|
||||
"f32_expm1minus_ulp_eval"
|
||||
"f32_extexp_ulp_eval"
|
||||
"f32_sigmoid_ulp_eval"
|
||||
"f32_sqrt_ulp_eval"
|
||||
"f32_tanh_ulp_eval"
|
||||
)
|
||||
|
||||
# Only Download
|
||||
ExternalProject_Add(xnnpack-download
|
||||
PREFIX xnnpack
|
||||
GIT_REPOSITORY https://github.com/google/XNNPACK.git
|
||||
GIT_TAG 4570a7151aa4f3e57eca14a575eeff6bb13e26be
|
||||
GIT_TAG b9d4073a6913891ce9cbd8965c8d506075d2a45a
|
||||
GIT_PROGRESS ON
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack
|
||||
UPDATE_COMMAND git restore .
|
||||
&& cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/google3/third_party/XNNPACK/microkernels.bzl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/
|
||||
&& git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch
|
||||
UPDATE_COMMAND ""
|
||||
PATCH_COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch
|
||||
CONFIGURE_COMMAND ""
|
||||
# grep xnnpack_benchmark -A 1 BUILD.bazel \
|
||||
# | grep "name =" \
|
||||
# | awk '{print $3}' \
|
||||
# | sed -e 's/\"//g' -e 's/,//g' -e 's/^/\/\/:/g'
|
||||
BUILD_COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack
|
||||
&& bazel --output_user_root=build-user-output build -c opt --config=wasm
|
||||
//:qs8_dwconv_bench.wasm
|
||||
//:qs8_f32_vcvt_bench.wasm
|
||||
//:qs8_gemm_bench.wasm
|
||||
//:qs8_requantization_bench.wasm
|
||||
//:qs8_vadd_bench.wasm
|
||||
//:qs8_vaddc_bench.wasm
|
||||
//:qs8_vcvt_bench.wasm
|
||||
//:qs8_vlrelu_bench.wasm
|
||||
//:qs8_vmul_bench.wasm
|
||||
//:qs8_vmulc_bench.wasm
|
||||
//:qu8_f32_vcvt_bench.wasm
|
||||
//:qu8_gemm_bench.wasm
|
||||
//:qu8_requantization_bench.wasm
|
||||
//:qu8_vadd_bench.wasm
|
||||
//:qu8_vaddc_bench.wasm
|
||||
//:qu8_vcvt_bench.wasm
|
||||
//:qu8_vlrelu_bench.wasm
|
||||
//:qu8_vmul_bench.wasm
|
||||
//:qu8_vmulc_bench.wasm
|
||||
//:bf16_gemm_bench.wasm
|
||||
//:f16_igemm_bench.wasm
|
||||
//:f16_gemm_bench.wasm
|
||||
//:f16_raddstoreexpminusmax_bench.wasm
|
||||
//:f16_spmm_bench.wasm
|
||||
//:f16_vsigmoid_bench.wasm
|
||||
//:f16_f32_vcvt_bench.wasm
|
||||
//:f32_igemm_bench.wasm
|
||||
//:f32_conv_hwc_bench.wasm
|
||||
//:f16_conv_hwc2chw_bench.wasm
|
||||
//:f16_gavgpool_cw_bench.wasm
|
||||
//:f32_gavgpool_cw_bench.wasm
|
||||
//:f32_conv_hwc2chw_bench.wasm
|
||||
//:f16_dwconv_bench.wasm
|
||||
//:f32_dwconv_bench.wasm
|
||||
//:f32_dwconv2d_chw_bench.wasm
|
||||
//:f16_dwconv2d_chw_bench.wasm
|
||||
//:f32_f16_vcvt_bench.wasm
|
||||
//:xx_transpose_bench.wasm
|
||||
//:x8_transpose_bench.wasm
|
||||
//:x16_transpose_bench.wasm
|
||||
//:x24_transpose_bench.wasm
|
||||
//:x32_transpose_bench.wasm
|
||||
//:x64_transpose_bench.wasm
|
||||
//:f32_gemm_bench.wasm
|
||||
//:f32_qs8_vcvt_bench.wasm
|
||||
//:f32_qu8_vcvt_bench.wasm
|
||||
//:f32_raddexpminusmax_bench.wasm
|
||||
//:f32_raddextexp_bench.wasm
|
||||
//:f32_raddstoreexpminusmax_bench.wasm
|
||||
//:f32_rmax_bench.wasm
|
||||
//:f32_spmm_bench.wasm
|
||||
//:f32_softmax_bench.wasm
|
||||
//:f16_velu_bench.wasm
|
||||
//:f32_velu_bench.wasm
|
||||
//:f32_vhswish_bench.wasm
|
||||
//:f32_vlrelu_bench.wasm
|
||||
//:f32_vrelu_bench.wasm
|
||||
//:f32_vscaleexpminusmax_bench.wasm
|
||||
//:f32_vscaleextexp_bench.wasm
|
||||
//:f32_vsigmoid_bench.wasm
|
||||
//:f16_vsqrt_bench.wasm
|
||||
//:f32_vsqrt_bench.wasm
|
||||
//:f32_im2col_gemm_bench.wasm
|
||||
//:rounding_bench.wasm
|
||||
//:s16_rmaxabs_bench.wasm
|
||||
//:s16_window_bench.wasm
|
||||
//:u32_filterbank_accumulate_bench.wasm
|
||||
//:u32_filterbank_subtract_bench.wasm
|
||||
//:u32_vlog_bench.wasm
|
||||
//:u64_u32_vsqrtshift_bench.wasm
|
||||
//:i16_vlshift_bench.wasm
|
||||
//:cs16_vsquareabs_bench.wasm
|
||||
//:cs16_bfly4_bench.wasm
|
||||
//:cs16_fftr_bench.wasm
|
||||
//:x8_lut_bench.wasm
|
||||
//:abs_bench.wasm
|
||||
//:average_pooling_bench.wasm
|
||||
//:bankers_rounding_bench.wasm
|
||||
//:ceiling_bench.wasm
|
||||
//:channel_shuffle_bench.wasm
|
||||
//:convert_bench.wasm
|
||||
//:convolution_bench.wasm
|
||||
//:deconvolution_bench.wasm
|
||||
//:elu_bench.wasm
|
||||
//:floor_bench.wasm
|
||||
//:global_average_pooling_bench.wasm
|
||||
//:hardswish_bench.wasm
|
||||
//:leaky_relu_bench.wasm
|
||||
//:max_pooling_bench.wasm
|
||||
//:negate_bench.wasm
|
||||
//:sigmoid_bench.wasm
|
||||
//:prelu_bench.wasm
|
||||
//:softmax_bench.wasm
|
||||
//:square_bench.wasm
|
||||
//:square_root_bench.wasm
|
||||
//:truncation_bench.wasm
|
||||
//:f16_gemm_e2e_bench.wasm
|
||||
//:f32_dwconv_e2e_bench.wasm
|
||||
//:f32_gemm_e2e_bench.wasm
|
||||
//:qs8_dwconv_e2e_bench.wasm
|
||||
//:qs8_gemm_e2e_bench.wasm
|
||||
//:qu8_gemm_e2e_bench.wasm
|
||||
//:qu8_dwconv_e2e_bench.wasm
|
||||
//:end2end_bench.wasm
|
||||
//:f16_exp_ulp_eval.wasm
|
||||
//:f16_expminus_ulp_eval.wasm
|
||||
//:f16_expm1minus_ulp_eval.wasm
|
||||
//:f16_sigmoid_ulp_eval.wasm
|
||||
//:f16_sqrt_ulp_eval.wasm
|
||||
//:f32_exp_ulp_eval.wasm
|
||||
//:f32_expminus_ulp_eval.wasm
|
||||
//:f32_expm1minus_ulp_eval.wasm
|
||||
//:f32_extexp_ulp_eval.wasm
|
||||
//:f32_sigmoid_ulp_eval.wasm
|
||||
//:f32_sqrt_ulp_eval.wasm
|
||||
//:f32_tanh_ulp_eval.wasm
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/bazel-out/wasm-opt/bin/
|
||||
${CMAKE_BINARY_DIR}/wasm-opt
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
|
||||
set(WAMRC "${CMAKE_CURRENT_SOURCE_DIR}/../../../wamr-compiler/build/wamrc")
|
||||
if(EXISTS ${WAMRC})
|
||||
message("-- Will generate .aot")
|
||||
else()
|
||||
message("Will generate .wasm")
|
||||
endif()
|
||||
|
||||
foreach(BENCHMARK IN LISTS NATIVE_BENCHMARKS)
|
||||
string(CONCAT WASM_BENCHMARK "//:" ${BENCHMARK} "-wasm")
|
||||
string(CONCAT WASM_OUTPUT ${BENCHMARK} ".wasm")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${WASM_OUTPUT}
|
||||
COMMAND bazel --output_user_root=build-user-output build -c opt --config=wasm ${WASM_BENCHMARK}
|
||||
&& ${CMAKE_COMMAND} -E copy_if_different ./bazel-bin/${WASM_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${WASM_OUTPUT}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack
|
||||
DEPENDS xnnpack-download
|
||||
COMMENT "Generating ${WASM_OUTPUT} ..."
|
||||
)
|
||||
|
||||
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${CMAKE_CURRENT_BINARY_DIR}/${WASM_OUTPUT})
|
||||
|
||||
if(EXISTS ${WAMRC})
|
||||
string(CONCAT AOT_OUTPUT ${BENCHMARK} ".aot")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${AOT_OUTPUT}
|
||||
COMMAND ${WAMRC} -o ${AOT_OUTPUT} ${WASM_OUTPUT}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS ${WASM_OUTPUT}
|
||||
COMMENT "Generating ${AOT_OUTPUT} ..."
|
||||
)
|
||||
|
||||
add_custom_target(${BENCHMARK} ALL DEPENDS ${AOT_OUTPUT})
|
||||
else()
|
||||
add_custom_target(${BENCHMARK} ALL DEPENDS ${WASM_OUTPUT})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
|
|
|
@ -9,26 +9,7 @@ please refer to [installation instructions](../README.md).
|
|||
|
||||
## Build XNNPACK
|
||||
|
||||
```bash
|
||||
cd <wamr-dir>/samples/workload/XNNPACK
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
```
|
||||
The wasm files are generated under folder samples/workload/XNNPACK/xnnpack/bazel-bin.
|
||||
|
||||
## Run benchmarks
|
||||
|
||||
Firstly please build iwasm with simd, libc-emcc and lib-pthread support:
|
||||
|
||||
``` bash
|
||||
$ cd <wamr-dir>/product-mini/platforms/linux/
|
||||
$ mkdir build && cd build
|
||||
$ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1
|
||||
$ make
|
||||
```
|
||||
|
||||
And please build wamrc:
|
||||
please build wamrc:
|
||||
|
||||
``` bash
|
||||
cd <wamr-dir>/wamr-compiler
|
||||
|
@ -38,11 +19,31 @@ cmake ..
|
|||
make
|
||||
```
|
||||
|
||||
Then compile wasm file to aot file and run:
|
||||
And then build xnnpack standalone wasm files
|
||||
|
||||
``` shell
|
||||
$ cd <wamr-dir>/samples/workload/XNNPACK/xnnpack/bazel-bin
|
||||
$ wamrc -o average_pooling_bench.aot average_pooling_bench.wasm (or other wasm files)
|
||||
$ iwasm average_pooling_bench.aot
|
||||
```bash
|
||||
$ cd <wamr-dir>/samples/workload/XNNPACK
|
||||
$ cmake -S . -B build
|
||||
$ cmake --build build
|
||||
```
|
||||
|
||||
Generated .wasm(and .aot) files are under *samples/workload/XNNPACK/build*.
|
||||
|
||||
## Run benchmarks
|
||||
|
||||
Firstly please build iwasm with simd, libc-emcc and lib-pthread supporting:
|
||||
|
||||
``` bash
|
||||
$ cd <wamr-dir>/product-mini/platforms/linux/
|
||||
$ mkdir build && cd build
|
||||
$ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1
|
||||
$ make
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
``` shell
|
||||
$ cd <wamr-dir>/samples/workload/XNNPACK/build
|
||||
$ iwasm average_pooling_bench.aot # (or other aot files)
|
||||
```
|
||||
|
||||
|
|
|
@ -1,141 +1,138 @@
|
|||
diff --git a/.bazelrc b/.bazelrc
|
||||
index 688279da1..376996885 100644
|
||||
index fcaff1063..e61d53337 100644
|
||||
--- a/.bazelrc
|
||||
+++ b/.bazelrc
|
||||
@@ -53,4 +53,9 @@ build:ios_fat --watchos_cpus=armv7k
|
||||
build:macos --apple_platform_type=macos
|
||||
@@ -1,6 +1,7 @@
|
||||
# Basic build settings
|
||||
build --jobs 128
|
||||
build --cxxopt='-std=gnu++14'
|
||||
+build --incompatible_enable_cc_toolchain_resolution
|
||||
|
||||
# Sets the default Apple platform to macOS.
|
||||
build --apple_platform_type=macos
|
||||
@@ -55,3 +56,10 @@ build:macos --apple_platform_type=macos
|
||||
|
||||
build:macos_arm64 --config=macos
|
||||
-build:macos_arm64 --cpu=darwin_arm64
|
||||
\ No newline at end of file
|
||||
+build:macos_arm64 --cpu=darwin_arm64
|
||||
build:macos_arm64 --cpu=darwin_arm64
|
||||
+
|
||||
+# Emscripten configs
|
||||
+build:wasm --copt="-Wno-unused"
|
||||
+build:wasm --copt="-Wno-unused-function"
|
||||
+build:wasm --copt="-Wno-unused-but-set-variable"
|
||||
+build:wasm --cpu=wasm
|
||||
+build:wasm --features=wasm_simd
|
||||
+build:wasm --crosstool_top=@emsdk//emscripten_toolchain:everything
|
||||
+build:wasm --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
|
||||
diff --git a/WORKSPACE b/WORKSPACE
|
||||
index cd8960ffa..787e03ca8 100644
|
||||
index 2e568088b..3961371ca 100644
|
||||
--- a/WORKSPACE
|
||||
+++ b/WORKSPACE
|
||||
@@ -29,8 +29,9 @@ http_archive(
|
||||
# Google Benchmark library, used in micro-benchmarks.
|
||||
http_archive(
|
||||
name = "com_google_benchmark",
|
||||
- strip_prefix = "benchmark-main",
|
||||
- urls = ["https://github.com/google/benchmark/archive/main.zip"],
|
||||
+ sha256 = "1ba14374fddcd9623f126b1a60945e4deac4cdc4fb25a5f25e7f779e36f2db52",
|
||||
+ strip_prefix = "benchmark-d2a8a4ee41b923876c034afb939c4fc03598e622",
|
||||
+ urls = ["https://github.com/google/benchmark/archive/d2a8a4ee41b923876c034afb939c4fc03598e622.zip"],
|
||||
@@ -83,7 +83,23 @@ http_archive(
|
||||
)
|
||||
|
||||
# FP16 library, used for half-precision conversions
|
||||
@@ -92,8 +93,25 @@ http_archive(
|
||||
],
|
||||
)
|
||||
# Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable
|
||||
-android_ndk_repository(name = "androidndk")
|
||||
+# android_ndk_repository(name = "androidndk")
|
||||
|
||||
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
# Android SDK location and API is auto-detected from $ANDROID_HOME environment variable
|
||||
-android_sdk_repository(name = "androidsdk")
|
||||
+# android_sdk_repository(name = "androidsdk")
|
||||
+
|
||||
+http_archive(
|
||||
+ name = "emsdk",
|
||||
+ # Use emsdk-3.0.0 since the larger version may:
|
||||
+ # - compress the wasm file into a tar file but not directly generate wasm file
|
||||
+ # - generate incomplete implementation of libc API, e.g. throw exception in getentropy
|
||||
+ strip_prefix = "emsdk-3.0.0/bazel",
|
||||
+ url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/3.0.0.tar.gz",
|
||||
+ sha256 = "a41dccfd15be9e85f923efaa0ac21943cbab77ec8d39e52f25eca1ec61a9ac9e"
|
||||
+ sha256 = "5fa6f5eb45a4d50264610c4c9e1c155535359b63bfaad69b4e5101d16c1e7e32",
|
||||
+ strip_prefix = "emsdk-a896e3d066448b3530dbcaa48869fafefd738f57/bazel",
|
||||
+ url = "https://github.com/emscripten-core/emsdk/archive/a896e3d066448b3530dbcaa48869fafefd738f57.tar.gz",
|
||||
+)
|
||||
+
|
||||
+load("@emsdk//:deps.bzl", emsdk_deps = "deps")
|
||||
+emsdk_deps()
|
||||
+
|
||||
+load("@emsdk//:emscripten_deps.bzl", emsdk_emscripten_deps = "emscripten_deps")
|
||||
+emsdk_emscripten_deps()
|
||||
+emsdk_emscripten_deps(emscripten_version = "3.1.44")
|
||||
+
|
||||
# Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable
|
||||
-android_ndk_repository(name = "androidndk")
|
||||
+#android_ndk_repository(name = "androidndk")
|
||||
+load("@emsdk//:toolchains.bzl", "register_emscripten_toolchains")
|
||||
+register_emscripten_toolchains()
|
||||
diff --git a/bench/utils.cc b/bench/utils.cc
|
||||
index 3b32503a7..656845336 100644
|
||||
--- a/bench/utils.cc
|
||||
+++ b/bench/utils.cc
|
||||
@@ -456,3 +456,13 @@ CodeMemoryHelper::~CodeMemoryHelper() {
|
||||
|
||||
# Android SDK location and API is auto-detected from $ANDROID_HOME environment variable
|
||||
-android_sdk_repository(name = "androidsdk")
|
||||
+#android_sdk_repository(name = "androidsdk")
|
||||
} // namespace utils
|
||||
} // namespace benchmark
|
||||
+
|
||||
+
|
||||
+extern "C"
|
||||
+__attribute__((import_module("env"), import_name("getentropy"))) int import_getentropy(void* buffer, size_t length);
|
||||
+
|
||||
+extern "C"
|
||||
+int getentropy(void* buffer, size_t length)
|
||||
+{
|
||||
+ return import_getentropy(buffer, length);
|
||||
+}
|
||||
diff --git a/build_defs.bzl b/build_defs.bzl
|
||||
index b8217a18d..6f2d1675e 100644
|
||||
index 01b436eb7..2738fd50a 100644
|
||||
--- a/build_defs.bzl
|
||||
+++ b/build_defs.bzl
|
||||
@@ -380,7 +380,7 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []):
|
||||
explicitly specified.
|
||||
"""
|
||||
native.cc_binary(
|
||||
- name = name,
|
||||
+ name = name + ".wasm",
|
||||
srcs = srcs,
|
||||
copts = xnnpack_std_cxxopts() + [
|
||||
"-Iinclude",
|
||||
@@ -405,5 +405,5 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []):
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Build definitions and rules for XNNPACK."""
|
||||
|
||||
-load(":emscripten.bzl", "xnnpack_emscripten_benchmark_linkopts", "xnnpack_emscripten_deps", "xnnpack_emscripten_minimal_linkopts", "xnnpack_emscripten_test_linkopts")
|
||||
+load(":emscripten.bzl", "xnnpack_emscripten_benchmark_linkopts", "xnnpack_emscripten_deps", "xnnpack_emscripten_minimal_linkopts", "xnnpack_emscripten_test_linkopts", "xnnpack_emscripten_standalone_benchmark_linkopts")
|
||||
+load("@emsdk//emscripten_toolchain:wasm_rules.bzl", "wasm_cc_binary")
|
||||
|
||||
def xnnpack_visibility():
|
||||
"""Visibility of :XNNPACK target.
|
||||
@@ -393,7 +394,8 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []):
|
||||
"//conditions:default": ["-Wno-unused-function"],
|
||||
}) + copts,
|
||||
linkopts = select({
|
||||
- ":emscripten": xnnpack_emscripten_benchmark_linkopts(),
|
||||
+ ":emscripten": xnnpack_emscripten_standalone_benchmark_linkopts(),
|
||||
+ ":emscripten_wasmsimd": xnnpack_emscripten_standalone_benchmark_linkopts(),
|
||||
":windows_x86_64_mingw": ["-lshlwapi"],
|
||||
":windows_x86_64_msys": ["-lshlwapi"],
|
||||
"//conditions:default": [],
|
||||
@@ -405,5 +407,16 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []):
|
||||
":emscripten": xnnpack_emscripten_deps(),
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
- tags = tags,
|
||||
+ tags = tags,
|
||||
+ tags = tags,
|
||||
+ )
|
||||
+
|
||||
+ wasm_cc_binary(
|
||||
+ name = name + "-wasm",
|
||||
+ cc_target = ":" + name,
|
||||
+ threads = "off",
|
||||
+ simd = True,
|
||||
+ standalone= True,
|
||||
+ outputs = [
|
||||
+ name + ".wasm",
|
||||
+ ]
|
||||
)
|
||||
diff --git a/emscripten.bzl b/emscripten.bzl
|
||||
index f1557a7b1..7f964a094 100644
|
||||
index f1557a7b1..a3c4f93b9 100644
|
||||
--- a/emscripten.bzl
|
||||
+++ b/emscripten.bzl
|
||||
@@ -25,12 +25,19 @@ def xnnpack_emscripten_benchmark_linkopts():
|
||||
"""Emscripten-specific linkopts for benchmarks."""
|
||||
return [
|
||||
"-s ASSERTIONS=1",
|
||||
- "-s ENVIRONMENT=node,shell,web",
|
||||
- "-s ERROR_ON_UNDEFINED_SYMBOLS=1",
|
||||
- "-s EXIT_RUNTIME=1",
|
||||
@@ -33,6 +33,21 @@ def xnnpack_emscripten_benchmark_linkopts():
|
||||
"--pre-js $(location :preamble.js.lds)",
|
||||
]
|
||||
|
||||
+def xnnpack_emscripten_standalone_benchmark_linkopts():
|
||||
+ return [
|
||||
+ "-s ASSERTIONS=1",
|
||||
+ "-s ERROR_ON_UNDEFINED_SYMBOLS=0",
|
||||
"-s ALLOW_MEMORY_GROWTH=1",
|
||||
"-s TOTAL_MEMORY=536870912", # 512M
|
||||
- "--pre-js $(location :preamble.js.lds)",
|
||||
+ "-s ALLOW_MEMORY_GROWTH=1",
|
||||
+ "-s TOTAL_MEMORY=536870912", # 512M
|
||||
+ "-s USE_PTHREADS=0",
|
||||
+ "-s STANDALONE_WASM=1",
|
||||
+ "-Wno-unused",
|
||||
+ "-Wno-unused-variable",
|
||||
+ "-Wno-unused-command-line-argument",
|
||||
+ "-Wl,--export=__heap_base",
|
||||
+ "-Wl,--export=__data_end",
|
||||
+ "-Wl,--export=malloc",
|
||||
+ "-Wl,--export=free",
|
||||
+ "--oformat=wasm",
|
||||
]
|
||||
|
||||
+ ]
|
||||
+
|
||||
+
|
||||
def xnnpack_emscripten_deps():
|
||||
diff --git a/src/log.c b/src/log.c
|
||||
index 5715f2f85..4b3e4261b 100644
|
||||
--- a/src/log.c
|
||||
+++ b/src/log.c
|
||||
@@ -55,7 +55,7 @@
|
||||
#endif
|
||||
|
||||
#if XNN_LOG_TO_STDIO
|
||||
-static void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) {
|
||||
+void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) {
|
||||
char stack_buffer[XNN_LOG_STACK_BUFFER_SIZE];
|
||||
char* heap_buffer = NULL;
|
||||
char* out_buffer = &stack_buffer[0];
|
||||
diff --git a/third_party/cpuinfo.BUILD b/third_party/cpuinfo.BUILD
|
||||
index 1997f4e3a..5e03c43af 100644
|
||||
--- a/third_party/cpuinfo.BUILD
|
||||
+++ b/third_party/cpuinfo.BUILD
|
||||
@@ -150,7 +150,7 @@ cc_library(
|
||||
"src/arm/midr.h",
|
||||
],
|
||||
deps = [
|
||||
- "@clog",
|
||||
+ "//deps/clog"
|
||||
],
|
||||
)
|
||||
|
||||
@@ -352,5 +352,5 @@ config_setting(
|
||||
|
||||
config_setting(
|
||||
name = "emscripten",
|
||||
- values = {"crosstool_top": "//toolchain:emscripten"},
|
||||
+ values = {"crosstool_top": "@emsdk//emscripten_toolchain:everything"},
|
||||
)
|
||||
"""Emscripten-specific dependencies for unit tests and benchmarks."""
|
||||
return [
|
||||
|
|
488
test-tools/host-tool/external/cJSON/cJSON.c
vendored
488
test-tools/host-tool/external/cJSON/cJSON.c
vendored
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* cJSON */
|
||||
/* JSON parser in C. */
|
||||
|
@ -43,6 +43,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
|
||||
#ifdef ENABLE_LOCALES
|
||||
#include <locale.h>
|
||||
|
@ -58,9 +59,33 @@
|
|||
#include "cJSON.h"
|
||||
|
||||
/* define our own boolean type */
|
||||
#ifdef true
|
||||
#undef true
|
||||
#endif
|
||||
#define true ((cJSON_bool)1)
|
||||
|
||||
#ifdef false
|
||||
#undef false
|
||||
#endif
|
||||
#define false ((cJSON_bool)0)
|
||||
|
||||
/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has
|
||||
* been defined in math.h */
|
||||
#ifndef isinf
|
||||
#define isinf(d) (isnan((d - d)) && !isnan(d))
|
||||
#endif
|
||||
#ifndef isnan
|
||||
#define isnan(d) (d != d)
|
||||
#endif
|
||||
|
||||
#ifndef NAN
|
||||
#ifdef _WIN32
|
||||
#define NAN sqrt(-1.0)
|
||||
#else
|
||||
#define NAN 0.0 / 0.0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
const unsigned char *json;
|
||||
size_t position;
|
||||
|
@ -72,7 +97,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
|
|||
return (const char *)(global_error.json + global_error.position);
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item)
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item)
|
||||
{
|
||||
if (!cJSON_IsString(item)) {
|
||||
return NULL;
|
||||
|
@ -81,18 +106,27 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item)
|
|||
return item->valuestring;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item)
|
||||
{
|
||||
if (!cJSON_IsNumber(item)) {
|
||||
return (double)NAN;
|
||||
}
|
||||
|
||||
return item->valuedouble;
|
||||
}
|
||||
|
||||
/* This is a safeguard to prevent copy-pasters from using incompatible C and
|
||||
* header files */
|
||||
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) \
|
||||
|| (CJSON_VERSION_PATCH != 10)
|
||||
|| (CJSON_VERSION_PATCH != 16)
|
||||
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
|
||||
#endif
|
||||
|
||||
CJSON_PUBLIC(const char *) cJSON_Version(void)
|
||||
{
|
||||
static char version[15];
|
||||
snprintf(version, sizeof(version), "%i.%i.%i", CJSON_VERSION_MAJOR,
|
||||
CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
|
||||
sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR,
|
||||
CJSON_VERSION_PATCH);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
@ -127,8 +161,8 @@ typedef struct internal_hooks {
|
|||
} internal_hooks;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/* work around MSVC error C2322: '...' address of dillimport '...'
|
||||
is not static */
|
||||
/* work around MSVC error C2322: '...' address of dllimport '...' is not static
|
||||
*/
|
||||
static void *CJSON_CDECL
|
||||
internal_malloc(size_t size)
|
||||
{
|
||||
|
@ -150,13 +184,11 @@ internal_realloc(void *pointer, size_t size)
|
|||
#define internal_realloc realloc
|
||||
#endif
|
||||
|
||||
/* clang-format off */
|
||||
static internal_hooks global_hooks = {
|
||||
internal_malloc,
|
||||
internal_free,
|
||||
internal_realloc
|
||||
};
|
||||
/* clang-format on */
|
||||
/* strlen of character literals resolved at compile time */
|
||||
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
|
||||
|
||||
static internal_hooks global_hooks = { internal_malloc, internal_free,
|
||||
internal_realloc };
|
||||
|
||||
static unsigned char *
|
||||
cJSON_strdup(const unsigned char *string, const internal_hooks *const hooks)
|
||||
|
@ -271,8 +303,8 @@ typedef struct {
|
|||
/* get a pointer to the buffer at the position */
|
||||
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
|
||||
|
||||
/* Parse the input text to generate a number, and populate the result
|
||||
into item. */
|
||||
/* Parse the input text to generate a number, and populate the result into item.
|
||||
*/
|
||||
static cJSON_bool
|
||||
parse_number(cJSON *const item, parse_buffer *const input_buffer)
|
||||
{
|
||||
|
@ -287,9 +319,8 @@ parse_number(cJSON *const item, parse_buffer *const input_buffer)
|
|||
}
|
||||
|
||||
/* copy the number into a temporary buffer and replace '.' with the decimal
|
||||
* point of the current locale (for strtod)
|
||||
* This also takes care of '\0' not necessarily being available for marking
|
||||
* the end of the input */
|
||||
* point of the current locale (for strtod) This also takes care of '\0' not
|
||||
* necessarily being available for marking the end of the input */
|
||||
for (i = 0; (i < (sizeof(number_c_string) - 1))
|
||||
&& can_access_at_index(input_buffer, i);
|
||||
i++) {
|
||||
|
@ -363,6 +394,32 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
|
|||
return object->valuedouble = number;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(char *)
|
||||
cJSON_SetValuestring(cJSON *object, const char *valuestring)
|
||||
{
|
||||
char *copy = NULL;
|
||||
/* if object's type is not cJSON_String or is cJSON_IsReference, it should
|
||||
* not set valuestring */
|
||||
if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) {
|
||||
return NULL;
|
||||
}
|
||||
if (strlen(valuestring) <= strlen(object->valuestring)) {
|
||||
strcpy(object->valuestring, valuestring);
|
||||
return object->valuestring;
|
||||
}
|
||||
copy =
|
||||
(char *)cJSON_strdup((const unsigned char *)valuestring, &global_hooks);
|
||||
if (copy == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (object->valuestring != NULL) {
|
||||
cJSON_free(object->valuestring);
|
||||
}
|
||||
object->valuestring = copy;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned char *buffer;
|
||||
size_t length;
|
||||
|
@ -438,9 +495,8 @@ ensure(printbuffer *const p, size_t needed)
|
|||
|
||||
return NULL;
|
||||
}
|
||||
if (newbuffer) {
|
||||
memcpy(newbuffer, p->buffer, p->offset + 1);
|
||||
}
|
||||
|
||||
memcpy(newbuffer, p->buffer, p->offset + 1);
|
||||
p->hooks.deallocate(p->buffer);
|
||||
}
|
||||
p->length = newsize;
|
||||
|
@ -463,6 +519,14 @@ update_offset(printbuffer *const buffer)
|
|||
buffer->offset += strlen((const char *)buffer_pointer);
|
||||
}
|
||||
|
||||
/* securely comparison of floating-point variables */
|
||||
static cJSON_bool
|
||||
compare_double(double a, double b)
|
||||
{
|
||||
double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
|
||||
return (fabs(a - b) <= maxVal * DBL_EPSILON);
|
||||
}
|
||||
|
||||
/* Render the number nicely from the given item into a string. */
|
||||
static cJSON_bool
|
||||
print_number(const cJSON *const item, printbuffer *const output_buffer)
|
||||
|
@ -471,35 +535,37 @@ print_number(const cJSON *const item, printbuffer *const output_buffer)
|
|||
double d = item->valuedouble;
|
||||
int length = 0;
|
||||
size_t i = 0;
|
||||
unsigned char
|
||||
number_buffer[26]; /* temporary buffer to print the number into */
|
||||
unsigned char number_buffer[26] = {
|
||||
0
|
||||
}; /* temporary buffer to print the number into */
|
||||
unsigned char decimal_point = get_decimal_point();
|
||||
double test;
|
||||
double test = 0.0;
|
||||
|
||||
if (output_buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This checks for NaN and Infinity */
|
||||
if ((d * 0) != 0) {
|
||||
length = snprintf((char *)number_buffer, sizeof(number_buffer), "null");
|
||||
if (isnan(d) || isinf(d)) {
|
||||
length = sprintf((char *)number_buffer, "null");
|
||||
}
|
||||
else if (d == (double)item->valueint) {
|
||||
length = sprintf((char *)number_buffer, "%d", item->valueint);
|
||||
}
|
||||
else {
|
||||
/* Try 15 decimal places of precision to avoid nonsignificant nonzero
|
||||
* digits */
|
||||
length =
|
||||
snprintf((char *)number_buffer, sizeof(number_buffer), "%1.15g", d);
|
||||
length = sprintf((char *)number_buffer, "%1.15g", d);
|
||||
|
||||
/* Check whether the original double can be recovered */
|
||||
if ((sscanf((char *)number_buffer, "%lg", &test) != 1)
|
||||
|| ((double)test != d)) {
|
||||
|| !compare_double((double)test, d)) {
|
||||
/* If not, print with 17 decimal places of precision */
|
||||
length = snprintf((char *)number_buffer, sizeof(number_buffer),
|
||||
"%1.17g", d);
|
||||
length = sprintf((char *)number_buffer, "%1.17g", d);
|
||||
}
|
||||
}
|
||||
|
||||
/* snprintf failed or buffer overrun occured */
|
||||
/* sprintf failed or buffer overrun occurred */
|
||||
if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -709,8 +775,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer)
|
|||
if (((size_t)(input_end - input_buffer->content)
|
||||
>= input_buffer->length)
|
||||
|| (*input_end != '\"')) {
|
||||
goto fail;
|
||||
/* string ended unexpectedly */
|
||||
goto fail; /* string ended unexpectedly */
|
||||
}
|
||||
|
||||
/* This is at most how much we need for the output */
|
||||
|
@ -719,8 +784,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer)
|
|||
output = (unsigned char *)input_buffer->hooks.allocate(allocation_length
|
||||
+ sizeof(""));
|
||||
if (output == NULL) {
|
||||
goto fail;
|
||||
/* allocation failure */
|
||||
goto fail; /* allocation failure */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,7 +823,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer)
|
|||
*output_pointer++ = input_pointer[1];
|
||||
break;
|
||||
|
||||
/* UTF-16 literal */
|
||||
/* UTF-16 literal */
|
||||
case 'u':
|
||||
sequence_length = utf16_literal_to_utf8(
|
||||
input_pointer, input_end, &output_pointer);
|
||||
|
@ -805,7 +869,7 @@ print_string_ptr(const unsigned char *const input,
|
|||
printbuffer *const output_buffer)
|
||||
{
|
||||
const unsigned char *input_pointer = NULL;
|
||||
unsigned char *output = NULL, *output_end;
|
||||
unsigned char *output = NULL;
|
||||
unsigned char *output_pointer = NULL;
|
||||
size_t output_length = 0;
|
||||
/* numbers of additional characters needed for escaping */
|
||||
|
@ -853,7 +917,6 @@ print_string_ptr(const unsigned char *const input,
|
|||
if (output == NULL) {
|
||||
return false;
|
||||
}
|
||||
output_end = output + output_length + sizeof("\"\"");
|
||||
|
||||
/* no characters have to be escaped */
|
||||
if (escape_characters == 0) {
|
||||
|
@ -902,9 +965,7 @@ print_string_ptr(const unsigned char *const input,
|
|||
break;
|
||||
default:
|
||||
/* escape and print as unicode codepoint */
|
||||
snprintf((char *)output_pointer,
|
||||
output_end - output_pointer, "u%04x",
|
||||
*input_pointer);
|
||||
sprintf((char *)output_pointer, "u%04x", *input_pointer);
|
||||
output_pointer += 4;
|
||||
break;
|
||||
}
|
||||
|
@ -945,6 +1006,10 @@ buffer_skip_whitespace(parse_buffer *const buffer)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (cannot_access_at_index(buffer, 0)) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
while (can_access_at_index(buffer, 0)
|
||||
&& (buffer_at_offset(buffer)[0] <= 32)) {
|
||||
buffer->offset++;
|
||||
|
@ -975,10 +1040,28 @@ skip_utf8_bom(parse_buffer *const buffer)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
/* Parse an object - create a new root, and populate. */
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_ParseWithOpts(const char *value, const char **return_parse_end,
|
||||
cJSON_bool require_null_terminated)
|
||||
{
|
||||
size_t buffer_length;
|
||||
|
||||
if (NULL == value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Adding null character size due to require_null_terminated. */
|
||||
buffer_length = strlen(value) + sizeof("");
|
||||
|
||||
return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end,
|
||||
require_null_terminated);
|
||||
}
|
||||
|
||||
/* Parse an object - create a new root, and populate. */
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length,
|
||||
const char **return_parse_end,
|
||||
cJSON_bool require_null_terminated)
|
||||
{
|
||||
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
cJSON *item = NULL;
|
||||
|
@ -987,12 +1070,12 @@ cJSON_ParseWithOpts(const char *value, const char **return_parse_end,
|
|||
global_error.json = NULL;
|
||||
global_error.position = 0;
|
||||
|
||||
if (value == NULL) {
|
||||
if (value == NULL || 0 == buffer_length) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
buffer.content = (const unsigned char *)value;
|
||||
buffer.length = strlen((const char *)value) + sizeof("");
|
||||
buffer.length = buffer_length;
|
||||
buffer.offset = 0;
|
||||
buffer.hooks = global_hooks;
|
||||
|
||||
|
@ -1056,7 +1139,13 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
|
|||
return cJSON_ParseWithOpts(value, 0, 0);
|
||||
}
|
||||
|
||||
#define cjson_min(a, b) ((a < b) ? a : b)
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_ParseWithLength(const char *value, size_t buffer_length)
|
||||
{
|
||||
return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
|
||||
}
|
||||
|
||||
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
static unsigned char *
|
||||
print(const cJSON *const item, cJSON_bool format,
|
||||
|
@ -1113,6 +1202,10 @@ fail:
|
|||
hooks->deallocate(buffer->buffer);
|
||||
}
|
||||
|
||||
if (printed != NULL) {
|
||||
hooks->deallocate(printed);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1156,20 +1249,20 @@ cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
|
|||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_PrintPreallocated(cJSON *item, char *buf, const int len,
|
||||
const cJSON_bool fmt)
|
||||
cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length,
|
||||
const cJSON_bool format)
|
||||
{
|
||||
printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
|
||||
|
||||
if ((len < 0) || (buf == NULL)) {
|
||||
if ((length < 0) || (buffer == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p.buffer = (unsigned char *)buf;
|
||||
p.length = (size_t)len;
|
||||
p.buffer = (unsigned char *)buffer;
|
||||
p.length = (size_t)length;
|
||||
p.offset = 0;
|
||||
p.noalloc = true;
|
||||
p.format = fmt;
|
||||
p.format = format;
|
||||
p.hooks = global_hooks;
|
||||
|
||||
return print_value(item, &p);
|
||||
|
@ -1341,8 +1434,7 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer)
|
|||
/* allocate next item */
|
||||
cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
|
||||
if (new_item == NULL) {
|
||||
goto fail;
|
||||
/* allocation failure */
|
||||
goto fail; /* allocation failure */
|
||||
}
|
||||
|
||||
/* attach next item to list */
|
||||
|
@ -1361,8 +1453,7 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer)
|
|||
input_buffer->offset++;
|
||||
buffer_skip_whitespace(input_buffer);
|
||||
if (!parse_value(current_item, input_buffer)) {
|
||||
goto fail;
|
||||
/* failed to parse value */
|
||||
goto fail; /* failed to parse value */
|
||||
}
|
||||
buffer_skip_whitespace(input_buffer);
|
||||
} while (can_access_at_index(input_buffer, 0)
|
||||
|
@ -1370,13 +1461,16 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer)
|
|||
|
||||
if (cannot_access_at_index(input_buffer, 0)
|
||||
|| buffer_at_offset(input_buffer)[0] != ']') {
|
||||
goto fail;
|
||||
/* expected end of array */
|
||||
goto fail; /* expected end of array */
|
||||
}
|
||||
|
||||
success:
|
||||
input_buffer->depth--;
|
||||
|
||||
if (head != NULL) {
|
||||
head->prev = current_item;
|
||||
}
|
||||
|
||||
item->type = cJSON_Array;
|
||||
item->child = head;
|
||||
|
||||
|
@ -1461,16 +1555,14 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
|
|||
|
||||
if (cannot_access_at_index(input_buffer, 0)
|
||||
|| (buffer_at_offset(input_buffer)[0] != '{')) {
|
||||
goto fail;
|
||||
/* not an object */
|
||||
goto fail; /* not an object */
|
||||
}
|
||||
|
||||
input_buffer->offset++;
|
||||
buffer_skip_whitespace(input_buffer);
|
||||
if (can_access_at_index(input_buffer, 0)
|
||||
&& (buffer_at_offset(input_buffer)[0] == '}')) {
|
||||
goto success;
|
||||
/* empty object */
|
||||
goto success; /* empty object */
|
||||
}
|
||||
|
||||
/* check if we skipped to the end of the buffer */
|
||||
|
@ -1486,8 +1578,7 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
|
|||
/* allocate next item */
|
||||
cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
|
||||
if (new_item == NULL) {
|
||||
goto fail;
|
||||
/* allocation failure */
|
||||
goto fail; /* allocation failure */
|
||||
}
|
||||
|
||||
/* attach next item to list */
|
||||
|
@ -1506,8 +1597,7 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
|
|||
input_buffer->offset++;
|
||||
buffer_skip_whitespace(input_buffer);
|
||||
if (!parse_string(current_item, input_buffer)) {
|
||||
goto fail;
|
||||
/* faile to parse name */
|
||||
goto fail; /* failed to parse name */
|
||||
}
|
||||
buffer_skip_whitespace(input_buffer);
|
||||
|
||||
|
@ -1517,16 +1607,14 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
|
|||
|
||||
if (cannot_access_at_index(input_buffer, 0)
|
||||
|| (buffer_at_offset(input_buffer)[0] != ':')) {
|
||||
goto fail;
|
||||
/* invalid object */
|
||||
goto fail; /* invalid object */
|
||||
}
|
||||
|
||||
/* parse the value */
|
||||
input_buffer->offset++;
|
||||
buffer_skip_whitespace(input_buffer);
|
||||
if (!parse_value(current_item, input_buffer)) {
|
||||
goto fail;
|
||||
/* failed to parse value */
|
||||
goto fail; /* failed to parse value */
|
||||
}
|
||||
buffer_skip_whitespace(input_buffer);
|
||||
} while (can_access_at_index(input_buffer, 0)
|
||||
|
@ -1534,13 +1622,16 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer)
|
|||
|
||||
if (cannot_access_at_index(input_buffer, 0)
|
||||
|| (buffer_at_offset(input_buffer)[0] != '}')) {
|
||||
goto fail;
|
||||
/* expected end of object */
|
||||
goto fail; /* expected end of object */
|
||||
}
|
||||
|
||||
success:
|
||||
input_buffer->depth--;
|
||||
|
||||
if (head != NULL) {
|
||||
head->prev = current_item;
|
||||
}
|
||||
|
||||
item->type = cJSON_Object;
|
||||
item->child = head;
|
||||
|
||||
|
@ -1792,22 +1883,26 @@ add_item_to_array(cJSON *array, cJSON *item)
|
|||
{
|
||||
cJSON *child = NULL;
|
||||
|
||||
if ((item == NULL) || (array == NULL)) {
|
||||
if ((item == NULL) || (array == NULL) || (array == item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
child = array->child;
|
||||
|
||||
/*
|
||||
* To find the last item in array quickly, we use prev in array
|
||||
*/
|
||||
if (child == NULL) {
|
||||
/* list is empty, start new one */
|
||||
array->child = item;
|
||||
item->prev = item;
|
||||
item->next = NULL;
|
||||
}
|
||||
else {
|
||||
/* append to the end */
|
||||
while (child->next) {
|
||||
child = child->next;
|
||||
if (child->prev) {
|
||||
suffix_object(child->prev, item);
|
||||
array->child->prev = item;
|
||||
}
|
||||
suffix_object(child, item);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1847,7 +1942,8 @@ add_item_to_object(cJSON *const object, const char *const string,
|
|||
char *new_key = NULL;
|
||||
int new_type = cJSON_Invalid;
|
||||
|
||||
if ((object == NULL) || (string == NULL) || (item == NULL)) {
|
||||
if ((object == NULL) || (string == NULL) || (item == NULL)
|
||||
|| (object == item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2028,7 +2124,7 @@ cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (item->prev != NULL) {
|
||||
if (item != parent->child) {
|
||||
/* not the first element */
|
||||
item->prev->next = item->next;
|
||||
}
|
||||
|
@ -2041,6 +2137,11 @@ cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item)
|
|||
/* first element */
|
||||
parent->child = item->next;
|
||||
}
|
||||
else if (item->next == NULL) {
|
||||
/* last element */
|
||||
parent->child->prev = item->prev;
|
||||
}
|
||||
|
||||
/* make sure the detached item doesn't point anywhere anymore */
|
||||
item->prev = NULL;
|
||||
item->next = NULL;
|
||||
|
@ -2121,7 +2222,8 @@ CJSON_PUBLIC(cJSON_bool)
|
|||
cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
|
||||
cJSON *replacement)
|
||||
{
|
||||
if ((parent == NULL) || (replacement == NULL) || (item == NULL)) {
|
||||
if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL)
|
||||
|| (item == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2135,12 +2237,24 @@ cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
|
|||
if (replacement->next != NULL) {
|
||||
replacement->next->prev = replacement;
|
||||
}
|
||||
if (replacement->prev != NULL) {
|
||||
replacement->prev->next = replacement;
|
||||
}
|
||||
if (parent->child == item) {
|
||||
if (parent->child->prev == parent->child) {
|
||||
replacement->prev = replacement;
|
||||
}
|
||||
parent->child = replacement;
|
||||
}
|
||||
else { /*
|
||||
* To find the last item in array quickly, we use prev in array.
|
||||
* We can't modify the last item's next pointer where this item was
|
||||
* the parent's child
|
||||
*/
|
||||
if (replacement->prev != NULL) {
|
||||
replacement->prev->next = replacement;
|
||||
}
|
||||
if (replacement->next == NULL) {
|
||||
parent->child->prev = replacement;
|
||||
}
|
||||
}
|
||||
|
||||
item->next = NULL;
|
||||
item->prev = NULL;
|
||||
|
@ -2149,15 +2263,15 @@ cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
|
|||
return true;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(void)
|
||||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
|
||||
{
|
||||
if (which < 0) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which),
|
||||
newitem);
|
||||
return cJSON_ReplaceItemViaPointer(
|
||||
array, get_array_item(array, (size_t)which), newitem);
|
||||
}
|
||||
|
||||
static cJSON_bool
|
||||
|
@ -2175,25 +2289,27 @@ replace_item_in_object(cJSON *object, const char *string, cJSON *replacement,
|
|||
}
|
||||
replacement->string =
|
||||
(char *)cJSON_strdup((const unsigned char *)string, &global_hooks);
|
||||
if (replacement->string == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
replacement->type &= ~cJSON_StringIsConst;
|
||||
|
||||
cJSON_ReplaceItemViaPointer(
|
||||
return cJSON_ReplaceItemViaPointer(
|
||||
object, get_object_item(object, string, case_sensitive), replacement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(void)
|
||||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
|
||||
{
|
||||
replace_item_in_object(object, string, newitem, false);
|
||||
return replace_item_in_object(object, string, newitem, false);
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(void)
|
||||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string,
|
||||
cJSON *newitem)
|
||||
{
|
||||
replace_item_in_object(object, string, newitem, true);
|
||||
return replace_item_in_object(object, string, newitem, true);
|
||||
}
|
||||
|
||||
/* Create basic types: */
|
||||
|
@ -2227,11 +2343,11 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
|
|||
return item;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
|
||||
{
|
||||
cJSON *item = cJSON_New_Item(&global_hooks);
|
||||
if (item) {
|
||||
item->type = b ? cJSON_True : cJSON_False;
|
||||
item->type = boolean ? cJSON_True : cJSON_False;
|
||||
}
|
||||
|
||||
return item;
|
||||
|
@ -2357,6 +2473,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
|
|||
}
|
||||
|
||||
a = cJSON_CreateArray();
|
||||
|
||||
for (i = 0; a && (i < (size_t)count); i++) {
|
||||
n = cJSON_CreateNumber(numbers[i]);
|
||||
if (!n) {
|
||||
|
@ -2372,6 +2489,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
|
|||
p = n;
|
||||
}
|
||||
|
||||
if (a && a->child) {
|
||||
a->child->prev = n;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
@ -2403,6 +2524,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
|
|||
p = n;
|
||||
}
|
||||
|
||||
if (a && a->child) {
|
||||
a->child->prev = n;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
@ -2434,10 +2559,15 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
|
|||
p = n;
|
||||
}
|
||||
|
||||
if (a && a->child) {
|
||||
a->child->prev = n;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_CreateStringArray(const char *const *strings, int count)
|
||||
{
|
||||
size_t i = 0;
|
||||
cJSON *n = NULL;
|
||||
|
@ -2465,6 +2595,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
|
|||
p = n;
|
||||
}
|
||||
|
||||
if (a && a->child) {
|
||||
a->child->prev = n;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
@ -2532,6 +2666,9 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
|
|||
}
|
||||
child = child->next;
|
||||
}
|
||||
if (newitem && newitem->child) {
|
||||
newitem->child->prev = newchild;
|
||||
}
|
||||
|
||||
return newitem;
|
||||
|
||||
|
@ -2543,55 +2680,93 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
skip_oneline_comment(char **input)
|
||||
{
|
||||
*input += static_strlen("//");
|
||||
|
||||
for (; (*input)[0] != '\0'; ++(*input)) {
|
||||
if ((*input)[0] == '\n') {
|
||||
*input += static_strlen("\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
skip_multiline_comment(char **input)
|
||||
{
|
||||
*input += static_strlen("/*");
|
||||
|
||||
for (; (*input)[0] != '\0'; ++(*input)) {
|
||||
if (((*input)[0] == '*') && ((*input)[1] == '/')) {
|
||||
*input += static_strlen("*/");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
minify_string(char **input, char **output)
|
||||
{
|
||||
(*output)[0] = (*input)[0];
|
||||
*input += static_strlen("\"");
|
||||
*output += static_strlen("\"");
|
||||
|
||||
for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
|
||||
(*output)[0] = (*input)[0];
|
||||
|
||||
if ((*input)[0] == '\"') {
|
||||
(*output)[0] = '\"';
|
||||
*input += static_strlen("\"");
|
||||
*output += static_strlen("\"");
|
||||
return;
|
||||
}
|
||||
else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
|
||||
(*output)[1] = (*input)[1];
|
||||
*input += static_strlen("\"");
|
||||
*output += static_strlen("\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json)
|
||||
{
|
||||
unsigned char *into = (unsigned char *)json;
|
||||
char *into = json;
|
||||
|
||||
if (json == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (*json) {
|
||||
if (*json == ' ') {
|
||||
json++;
|
||||
}
|
||||
else if (*json == '\t') {
|
||||
/* Whitespace characters. */
|
||||
json++;
|
||||
}
|
||||
else if (*json == '\r') {
|
||||
json++;
|
||||
}
|
||||
else if (*json == '\n') {
|
||||
json++;
|
||||
}
|
||||
else if ((*json == '/') && (json[1] == '/')) {
|
||||
/* double-slash comments, to end of line. */
|
||||
while (*json && (*json != '\n')) {
|
||||
while (json[0] != '\0') {
|
||||
switch (json[0]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
json++;
|
||||
}
|
||||
}
|
||||
else if ((*json == '/') && (json[1] == '*')) {
|
||||
/* multiline comments. */
|
||||
while (*json && !((*json == '*') && (json[1] == '/'))) {
|
||||
json++;
|
||||
}
|
||||
json += 2;
|
||||
}
|
||||
else if (*json == '\"') {
|
||||
/* string literals, which are \" sensitive. */
|
||||
*into++ = (unsigned char)*json++;
|
||||
while (*json && (*json != '\"')) {
|
||||
if (*json == '\\') {
|
||||
*into++ = (unsigned char)*json++;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
if (json[1] == '/') {
|
||||
skip_oneline_comment(&json);
|
||||
}
|
||||
*into++ = (unsigned char)*json++;
|
||||
}
|
||||
*into++ = (unsigned char)*json++;
|
||||
}
|
||||
else {
|
||||
/* All other characters. */
|
||||
*into++ = (unsigned char)*json++;
|
||||
else if (json[1] == '*') {
|
||||
skip_multiline_comment(&json);
|
||||
}
|
||||
else {
|
||||
json++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
minify_string(&json, (char **)&into);
|
||||
break;
|
||||
|
||||
default:
|
||||
into[0] = json[0];
|
||||
json++;
|
||||
into++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2692,8 +2867,7 @@ CJSON_PUBLIC(cJSON_bool)
|
|||
cJSON_Compare(const cJSON *const a, const cJSON *const b,
|
||||
const cJSON_bool case_sensitive)
|
||||
{
|
||||
if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))
|
||||
|| cJSON_IsInvalid(a)) {
|
||||
if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2726,7 +2900,7 @@ cJSON_Compare(const cJSON *const a, const cJSON *const b,
|
|||
return true;
|
||||
|
||||
case cJSON_Number:
|
||||
if (a->valuedouble == b->valuedouble) {
|
||||
if (compare_double(a->valuedouble, b->valuedouble)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
153
test-tools/host-tool/external/cJSON/cJSON.h
vendored
153
test-tools/host-tool/external/cJSON/cJSON.h
vendored
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
@ -35,30 +35,34 @@ extern "C" {
|
|||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/**
|
||||
* When compiling for windows, we specify a specific calling convention to avoid
|
||||
* issues where we are being called from a project with a different default
|
||||
* calling convention. For windows you have 3 define options:
|
||||
* CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever
|
||||
* dllexport symbols
|
||||
* CJSON_EXPORT_SYMBOLS - Define this on library build when you want to
|
||||
* dllexport symbols (default)
|
||||
* CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
*
|
||||
* For *nix builds that support visibility attribute, you can define similar
|
||||
* behavior by setting default visibility to hidden by adding
|
||||
* -fvisibility=hidden (for gcc)
|
||||
* or
|
||||
* -xldscope=hidden (for sun cc)
|
||||
* to CFLAGS, then using the CJSON_API_VISIBILITY flag to "export" the same
|
||||
* symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
*/
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid
|
||||
issues where we are being called from a project with a different default calling
|
||||
convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever
|
||||
dllexport symbols CJSON_EXPORT_SYMBOLS - Define this on library build when you
|
||||
want to dllexport symbols (default) CJSON_IMPORT_SYMBOLS - Define this if you
|
||||
want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar
|
||||
behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way
|
||||
CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and
|
||||
header file */
|
||||
* header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) \
|
||||
&& !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
|
@ -86,7 +90,7 @@ extern "C" {
|
|||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 10
|
||||
#define CJSON_VERSION_PATCH 16
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -107,11 +111,11 @@ extern "C" {
|
|||
/* The cJSON structure: */
|
||||
typedef struct cJSON {
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use
|
||||
GetArraySize/GetArrayItem/GetObjectItem */
|
||||
* GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of
|
||||
the items in the array/object. */
|
||||
* the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
|
@ -125,7 +129,7 @@ typedef struct cJSON {
|
|||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list
|
||||
of subitems of an object. */
|
||||
* of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
|
@ -140,7 +144,7 @@ typedef struct cJSON_Hooks {
|
|||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse
|
||||
them. This is to prevent stack overflows. */
|
||||
* them. This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
@ -159,6 +163,8 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks *hooks);
|
|||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate.
|
||||
*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null
|
||||
* terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then
|
||||
|
@ -167,6 +173,10 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
|||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_ParseWithOpts(const char *value, const char **return_parse_end,
|
||||
cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length,
|
||||
const char **return_parse_end,
|
||||
cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
|
@ -185,7 +195,7 @@ CJSON_PUBLIC(cJSON_bool)
|
|||
cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length,
|
||||
const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
|
@ -205,8 +215,9 @@ cJSON_HasObjectItem(const cJSON *object, const char *string);
|
|||
* when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check if the item is a string and return its valuestring */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON *const item);
|
||||
|
@ -233,18 +244,21 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
|||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
it will not be freed by cJSON_Delete */
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/arrray that only references it's elements so
|
||||
they will not be freed by cJSON_Delete */
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the
|
||||
* number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
|
@ -264,7 +278,7 @@ cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
|||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
|
@ -286,32 +300,35 @@ cJSON_InsertItemInArray(
|
|||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
|
||||
cJSON *replacement);
|
||||
CJSON_PUBLIC(void)
|
||||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(void)
|
||||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
|
||||
CJSON_PUBLIC(void)
|
||||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string,
|
||||
cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new
|
||||
memory that will need to be released. With recurse!=0, it will duplicate any
|
||||
children connected to the item. The item->next and ->prev pointers are always
|
||||
zero on return from Duplicate. */
|
||||
* memory that will need to be released. With recurse!=0, it will duplicate any
|
||||
* children connected to the item. The item->next and ->prev pointers are always
|
||||
* zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or
|
||||
* invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or
|
||||
* case insensitive (0) */
|
||||
* invalid, they will be considered unequal. case_sensitive determines if object
|
||||
* keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool)
|
||||
cJSON_Compare(const cJSON *const a, const cJSON *const b,
|
||||
const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from
|
||||
* strings. The input pointer json cannot point to a read-only address area,
|
||||
* such as a string constant, but should point to a readable and writable
|
||||
* address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
They return the added item or NULL on failure. */
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
cJSON_AddNullToObject(cJSON *const object, const char *const name);
|
||||
CJSON_PUBLIC(cJSON *)
|
||||
|
@ -336,7 +353,7 @@ CJSON_PUBLIC(cJSON *)
|
|||
cJSON_AddArrayToObject(cJSON *const object, const char *const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble
|
||||
too. */
|
||||
* too. */
|
||||
#define cJSON_SetIntValue(object, number) \
|
||||
((object) ? (object)->valueint = (object)->valuedouble = (number) \
|
||||
: (number))
|
||||
|
@ -345,6 +362,18 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
|||
#define cJSON_SetNumberValue(object, number) \
|
||||
((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) \
|
||||
: (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type
|
||||
* of object is cJSON_String */
|
||||
CJSON_PUBLIC(char *)
|
||||
cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns
|
||||
* cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) \
|
||||
((object != NULL && ((object)->type & (cJSON_False | cJSON_True))) \
|
||||
? (object)->type = ((object)->type & (~(cJSON_False | cJSON_True))) \
|
||||
| ((boolValue) ? cJSON_True : cJSON_False) \
|
||||
: cJSON_Invalid)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) \
|
||||
|
@ -352,7 +381,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
|||
element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with
|
||||
cJSON_InitHooks */
|
||||
* cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
|
|
|
@ -343,26 +343,6 @@ index adb5cb7..590f626 100644
|
|||
(func $g (param $x i32) (result i32)
|
||||
(i32.add (local.get $x) (i32.const 1))
|
||||
)
|
||||
diff --git a/test/core/select.wast b/test/core/select.wast
|
||||
index 046e6fe..b677023 100644
|
||||
--- a/test/core/select.wast
|
||||
+++ b/test/core/select.wast
|
||||
@@ -324,6 +324,7 @@
|
||||
(module (func $arity-0 (select (result) (nop) (nop) (i32.const 1))))
|
||||
"invalid result arity"
|
||||
)
|
||||
+(;
|
||||
(assert_invalid
|
||||
(module (func $arity-2 (result i32 i32)
|
||||
(select (result i32 i32)
|
||||
@@ -334,6 +335,7 @@
|
||||
))
|
||||
"invalid result arity"
|
||||
)
|
||||
+;)
|
||||
|
||||
|
||||
(assert_invalid
|
||||
diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast
|
||||
index 380e84e..f37e745 100644
|
||||
--- a/test/core/table_copy.wast
|
||||
|
|
|
@ -824,7 +824,7 @@ function trigger()
|
|||
collect_coverage llvm-jit
|
||||
|
||||
echo "work in orc jit lazy compilation mode"
|
||||
BUILD_FLAGS="$ORC_EAGER_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS"
|
||||
BUILD_FLAGS="$ORC_LAZY_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS"
|
||||
build_iwasm_with_cfg $BUILD_FLAGS
|
||||
for suite in "${TEST_CASE_ARR[@]}"; do
|
||||
$suite"_test" jit
|
||||
|
|
|
@ -11,7 +11,10 @@ readonly TARGET=$2
|
|||
readonly WORK_DIR=$PWD
|
||||
readonly PLATFORM=$(uname -s | tr A-Z a-z)
|
||||
readonly WAMR_DIR="${WORK_DIR}/../../../.."
|
||||
readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm"
|
||||
readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm \
|
||||
--allow-resolve=google-public-dns-a.google.com \
|
||||
--addr-pool=::1/128,127.0.0.1/32"
|
||||
readonly IWASM_CMD_STRESS="${IWASM_CMD} --max-threads=8"
|
||||
readonly WAMRC_CMD="${WORK_DIR}/../../../../wamr-compiler/build/wamrc"
|
||||
readonly C_TESTS="tests/c/testsuite/"
|
||||
readonly ASSEMBLYSCRIPT_TESTS="tests/assemblyscript/testsuite/"
|
||||
|
@ -22,6 +25,11 @@ readonly LIB_SOCKET_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-socket/test/"
|
|||
run_aot_tests () {
|
||||
local tests=("$@")
|
||||
for test_wasm in ${tests[@]}; do
|
||||
local extra_stress_flags=""
|
||||
if [[ "$test_wasm" =~ "stress" ]]; then
|
||||
extra_stress_flags="--max-threads=8"
|
||||
fi
|
||||
|
||||
test_aot="${test_wasm%.wasm}.aot"
|
||||
test_json="${test_wasm%.wasm}.json"
|
||||
|
||||
|
@ -35,12 +43,12 @@ run_aot_tests () {
|
|||
|
||||
echo "Running $test_aot"
|
||||
expected=0
|
||||
if [ -f ${test_json} ]; then
|
||||
if [ -f ${test_json} ]; then
|
||||
expected=$(jq .exit_code ${test_json})
|
||||
fi
|
||||
|
||||
${IWASM_CMD} $test_aot
|
||||
|
||||
|
||||
${IWASM_CMD} $extra_stress_flags $test_aot
|
||||
|
||||
ret=${PIPESTATUS[0]}
|
||||
|
||||
echo "expected=$expected, actual=$ret"
|
||||
|
@ -48,20 +56,36 @@ run_aot_tests () {
|
|||
exit_code=1
|
||||
fi
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
if [[ $MODE != "aot" ]];then
|
||||
python3 -m venv wasi-env && source wasi-env/bin/activate
|
||||
python3 -m pip install -r test-runner/requirements.txt
|
||||
|
||||
# Stress test requires max-threads=8 so it's run separately
|
||||
if [[ -e "${THREAD_INTERNAL_TESTS}spawn_stress_test.wasm" ]]; then
|
||||
${IWASM_CMD_STRESS} ${THREAD_INTERNAL_TESTS}spawn_stress_test.wasm
|
||||
ret=${PIPESTATUS[0]}
|
||||
if [ "${ret}" -ne 0 ]; then
|
||||
echo "Stress test spawn_stress_test FAILED with code " ${ret}
|
||||
exit_code=${ret}
|
||||
fi
|
||||
fi
|
||||
|
||||
TEST_RUNTIME_EXE="${IWASM_CMD}" python3 test-runner/wasi_test_runner.py \
|
||||
-r adapters/wasm-micro-runtime.py \
|
||||
-t \
|
||||
${C_TESTS} \
|
||||
${ASSEMBLYSCRIPT_TESTS} \
|
||||
${THREAD_PROPOSAL_TESTS} \
|
||||
${THREAD_INTERNAL_TESTS} \
|
||||
${LIB_SOCKET_TESTS} \
|
||||
exit_code=${PIPESTATUS[0]}
|
||||
-r adapters/wasm-micro-runtime.py \
|
||||
-t \
|
||||
${C_TESTS} \
|
||||
${ASSEMBLYSCRIPT_TESTS} \
|
||||
${THREAD_PROPOSAL_TESTS} \
|
||||
${THREAD_INTERNAL_TESTS} \
|
||||
${LIB_SOCKET_TESTS} \
|
||||
--exclude-filter "${THREAD_INTERNAL_TESTS}skip.json"
|
||||
|
||||
ret=${PIPESTATUS[0]}
|
||||
if [ "${ret}" -ne 0 ]; then
|
||||
exit_code=${ret}
|
||||
fi
|
||||
deactivate
|
||||
else
|
||||
target_option=""
|
||||
|
|
Loading…
Reference in New Issue
Block a user